stoneyr
驱动牛犊
驱动牛犊
  • 注册日期2002-01-13
  • 最后登录2007-10-31
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
阅读:6050回复:27

关于WDM驱动程序的一些问题,想了很久都没有想通,特来此问

楼主#
更多 发布于:2004-10-15 20:03
1、系统检测到硬件时调用AddDevice例程让驱动程序增加一个硬件设备,但是如果创建的驱动程序并不针

对任何一个硬件,那这个AddDevice例程是什么时候被调用的呢?系统为什么要调用这个例程呢?比如一

个只有DriverEntry和AddDevice两个函数的驱动程序,同样也可以正常编译,正常安装,安装好后却发现

系统也正常调用了AddDevice例程。
2、WDM驱动程序在AddDevice里创建了一个设备,并注册了设备接口,其目的是为了给上层应用程序提供

访问该设备的接口。那就说在上层应用程序使用这个设备之前,这个驱动程序早就已经被装载,并且系统

已经调用了其AddDevice例程,要不然的话上层应用程序就没有设备接口可用了。那这个驱动程序是在什

么时候被装载的?在操作系统启动的时候?还是......?在INF文件里有一个控制驱动装载的选项,有一

个值是在系统需要的时候装载该驱动,但是什么时候才是系统需要的时候呢?
3、驱动程序里的各个例程,是运行在与上层应用相同的线程上下文环境,还是操作系统内核另外开一个

线程来执行该例程?如果是前者,那么驱动程序是如果实现对IRP的延迟处理的,因为如果延迟了,那上

层应用中线程不是也被阻塞了吗?如果是后者,操作系统对每一个活动的例程都要开一个线程,那不是要

占用系统很多的资源,这样为什么不会影响系统的性能?
4、驱动程序的代码在整个系统中是不是只有一份?也就是说如果驱动程序里有一个全局变量,那么访问

该全局变量的所有例程都就应该同步或互斥,而不象dll(Win2K)中的全局变量,即使是全局变量如果不

声明在共享数据段内都不是共享的。

最新喜欢:

xie_jian_junxie_ji... netelifeneteli...
Pegram
论坛版主
论坛版主
  • 注册日期2005-12-03
  • 最后登录2013-08-23
  • 粉丝13
  • 关注5
  • 积分1333分
  • 威望4717点
  • 贡献值1点
  • 好评度78点
  • 原创分0分
  • 专家分2分
沙发#
发布于:2010-04-26 21:15
要看书啊!!
《寒江独钓》与《竹林蹊径》的合作作者。精通USB开发,设计了CY001 USB驱动套件(http://bbs.driverdevelop.com/read.php?tid-119314.html)。
oktsl
驱动牛犊
驱动牛犊
  • 注册日期2009-12-24
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望71点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2010-04-16 09:28
mark~
coffeemay
驱动牛犊
驱动牛犊
  • 注册日期2005-10-13
  • 最后登录2009-04-22
  • 粉丝0
  • 关注0
  • 积分22分
  • 威望23点
  • 贡献值0点
  • 好评度2点
  • 原创分0分
  • 专家分0分
地板#
发布于:2007-06-13 14:30
跟帖做个记号,以后好找
stoneyr
驱动牛犊
驱动牛犊
  • 注册日期2002-01-13
  • 最后登录2007-10-31
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
地下室#
发布于:2005-03-23 13:15
关键是一个先与后的问题呀,
应用程序总得要有接口才能通知PNP管理器调用DriverEntry,
但是在AddDevice里接口才被注册,
而在DriverEntry里才能通知到PNP管理器AddDevice的地址,

这样的话,刚开始的时候,应用程序怎么知道接口在哪呢?
Leonsoft
驱动小牛
驱动小牛
  • 注册日期2003-05-08
  • 最后登录2012-08-11
  • 粉丝1
  • 关注0
  • 积分21分
  • 威望281点
  • 贡献值1点
  • 好评度103点
  • 原创分0分
  • 专家分0分
5楼#
发布于:2005-03-23 11:57
[quote]1.PnP管理器为每个设备实例调用AddDevice routine,如果有设备的,首先要在inf文件里面指定加载的设备,如果一个设备也没有的话,嘿嘿,就像filter driver,你总要加到某个driver上去吧,所以AddDevice总会被调用的,才能生成设备栈,这样才符合WDM的构架。
2.何时load driver,由inf文件的start type来决定,如3,就是booting windows时候加载driver,如果为1,就是由自己的用户程序使用到driver的时候,来加载它,当然要有管理员的权限,通过CreateService,StartSerive来实现动态安装driver,其实就是交给system.exe来实现。
3.内核模式的例程运行在下面三种不同的上下文之一:
- 系统进程上下文
- 特定用户线程(和进程)上下文
- 任意用户线程(和进程)上下文
一个驱动程序的DriverEntry(…)函数总是运行在系统进程的上下文中,系统进程上下文和用户上下文无关(因此没有TEB)。DPCs(例如一个驱动程序为ISR服务的DPC或者定时器到期函数)运行在任意用户线程的上下文中。这意味者在一个DPC的执行过程中,任何用户线程都可以成为“当前”线程,因此任何用户进程都可以映射到内核虚拟地址空间的低2GB中。当一个设备直接被用户访问而不涉及其他驱动程序时,该设备的驱动程序的分派线程总是运行在发出请求的用户线程中。
4.DriverEntry只会被调用一次,AddDevice可以被多个设备调用,so,DeviceExterntion对应每一个设备。全局变量只有一个,so,必须作互斥访问。

以上只是个人理解,可能有不对的地方,还请高人指教。


好,要的就是你这样的回答。
但是对于第二个问题,可能是我没有表达清楚,还有一个重点的小问题在里面:由于是在AddDevice里调用IoRegisterDeviceInterface的,而AddDevice是在DriverEntry以后才会被调用,而这个DeviceInterface是提供给就用程序的,就用程序只有找到该DeviceInterface后才能启动驱动程序(我们暂时不说在系统启动时加载的那种类型),这样才能调用DriverEntry,再调用AddDevice,再调用IoRegisterDeviceInterface,那这个不就是一个鸡生蛋,蛋生鸡的问题了吗? [/quote]

DriverEntry 和AddDevice的调用由PnP management来掌控。

哥们,请给分阿,嘿嘿。
I will do the best with what the God gave me.
tigerL
驱动小牛
驱动小牛
  • 注册日期2003-12-24
  • 最后登录2008-10-28
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望23点
  • 贡献值0点
  • 好评度19点
  • 原创分0分
  • 专家分0分
6楼#
发布于:2005-03-22 22:32

好,要的就是你这样的回答。
但是对于第二个问题,可能是我没有表达清楚,还有一个重点的小问题在里面:由于是在AddDevice里调用IoRegisterDeviceInterface的,而AddDevice是在DriverEntry以后才会被调用,而这个DeviceInterface是提供给就用程序的,就用程序只有找到该DeviceInterface后才能启动驱动程序(我们暂时不说在系统启动时加载的那种类型),这样才能调用DriverEntry,再调用AddDevice,再调用IoRegisterDeviceInterface,那这个不就是一个鸡生蛋,蛋生鸡的问题了吗?


驱动程序不是由应用程序启动的。DeviceInterface只是用来获得访问驱动程序所创建设备对象的句柄而已,它与驱动程序的启动无关。
关于驱动程序的启动,可以参看ddk文档,里面有比较详尽的解说。
省元坊
stoneyr
驱动牛犊
驱动牛犊
  • 注册日期2002-01-13
  • 最后登录2007-10-31
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
7楼#
发布于:2005-03-22 18:46
1.PnP管理器为每个设备实例调用AddDevice routine,如果有设备的,首先要在inf文件里面指定加载的设备,如果一个设备也没有的话,嘿嘿,就像filter driver,你总要加到某个driver上去吧,所以AddDevice总会被调用的,才能生成设备栈,这样才符合WDM的构架。
2.何时load driver,由inf文件的start type来决定,如3,就是booting windows时候加载driver,如果为1,就是由自己的用户程序使用到driver的时候,来加载它,当然要有管理员的权限,通过CreateService,StartSerive来实现动态安装driver,其实就是交给system.exe来实现。
3.内核模式的例程运行在下面三种不同的上下文之一:
- 系统进程上下文
- 特定用户线程(和进程)上下文
- 任意用户线程(和进程)上下文
一个驱动程序的DriverEntry(…)函数总是运行在系统进程的上下文中,系统进程上下文和用户上下文无关(因此没有TEB)。DPCs(例如一个驱动程序为ISR服务的DPC或者定时器到期函数)运行在任意用户线程的上下文中。这意味者在一个DPC的执行过程中,任何用户线程都可以成为“当前”线程,因此任何用户进程都可以映射到内核虚拟地址空间的低2GB中。当一个设备直接被用户访问而不涉及其他驱动程序时,该设备的驱动程序的分派线程总是运行在发出请求的用户线程中。
4.DriverEntry只会被调用一次,AddDevice可以被多个设备调用,so,DeviceExterntion对应每一个设备。全局变量只有一个,so,必须作互斥访问。

以上只是个人理解,可能有不对的地方,还请高人指教。


好,要的就是你这样的回答。
但是对于第二个问题,可能是我没有表达清楚,还有一个重点的小问题在里面:由于是在AddDevice里调用IoRegisterDeviceInterface的,而AddDevice是在DriverEntry以后才会被调用,而这个DeviceInterface是提供给就用程序的,就用程序只有找到该DeviceInterface后才能启动驱动程序(我们暂时不说在系统启动时加载的那种类型),这样才能调用DriverEntry,再调用AddDevice,再调用IoRegisterDeviceInterface,那这个不就是一个鸡生蛋,蛋生鸡的问题了吗?
Leonsoft
驱动小牛
驱动小牛
  • 注册日期2003-05-08
  • 最后登录2012-08-11
  • 粉丝1
  • 关注0
  • 积分21分
  • 威望281点
  • 贡献值1点
  • 好评度103点
  • 原创分0分
  • 专家分0分
8楼#
发布于:2005-03-22 13:13
1.PnP管理器为每个设备实例调用AddDevice routine,如果有设备的,首先要在inf文件里面指定加载的设备,如果一个设备也没有的话,嘿嘿,就像filter driver,你总要加到某个driver上去吧,所以AddDevice总会被调用的,才能生成设备栈,这样才符合WDM的构架。
2.何时load driver,由inf文件的start type来决定,如3,就是booting windows时候加载driver,如果为1,就是由自己的用户程序使用到driver的时候,来加载它,当然要有管理员的权限,通过CreateService,StartSerive来实现动态安装driver,其实就是交给system.exe来实现。
3.内核模式的例程运行在下面三种不同的上下文之一:
- 系统进程上下文
- 特定用户线程(和进程)上下文
- 任意用户线程(和进程)上下文
一个驱动程序的DriverEntry(…)函数总是运行在系统进程的上下文中,系统进程上下文和用户上下文无关(因此没有TEB)。DPCs(例如一个驱动程序为ISR服务的DPC或者定时器到期函数)运行在任意用户线程的上下文中。这意味者在一个DPC的执行过程中,任何用户线程都可以成为“当前”线程,因此任何用户进程都可以映射到内核虚拟地址空间的低2GB中。当一个设备直接被用户访问而不涉及其他驱动程序时,该设备的驱动程序的分派线程总是运行在发出请求的用户线程中。
4.DriverEntry只会被调用一次,AddDevice可以被多个设备调用,so,DeviceExterntion对应每一个设备。全局变量只有一个,so,必须作互斥访问。

以上只是个人理解,可能有不对的地方,还请高人指教。
I will do the best with what the God gave me.
qinxg
驱动小牛
驱动小牛
  • 注册日期2002-11-15
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分37分
  • 威望27点
  • 贡献值0点
  • 好评度5点
  • 原创分0分
  • 专家分0分
9楼#
发布于:2005-03-22 09:36
我的理解:
1.无硬件的AddDevice: 是inf安装时写入了注册表:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Class里实现的.Windows会读这个,实现AddDevice

2.inf文件指定的

3.驱动是系统自己开的线程.驱动里也可以开别的线程,特别是在处理PASSIVE_LEVEL上的函数时,有时非开线程不可

4.全局变量是唯一的,一定要加互斥保护
wqmmmmm
驱动牛犊
驱动牛犊
  • 注册日期2004-09-09
  • 最后登录2016-01-09
  • 粉丝0
  • 关注0
  • 积分44分
  • 威望5点
  • 贡献值0点
  • 好评度4点
  • 原创分0分
  • 专家分0分
10楼#
发布于:2005-03-21 13:24
这几个问题..你应该翻翻前面的帖子....

第一个问题显得很庞大...你可以到windows源码版看看我发的那个device tree的建立过程的帖子

第二个问题同上..同一篇文章里面有解释

第三个问题...有很多种情况..有一部分是在调用你的driver的线程环境里面执行的...如果你的driver调用了waitxx一类的函数..那么就发生了线程切换..到了另外的一个线程..当你waitxx一类函数条件满足的时候...又轮到你的函数执行...这个部分..并不会创建线程.具体的讲..就多了..涉及到线程切换..涉及到waitxx函数的实现..apc等等的东西...你看看windows 2000的源代码吧...有机会我也会准备一篇关于线程调度的文章出来...

第四个问题...驱动的代码确实只有一份..全局变量确实是放到nonpage memory上的(默认情况)..确实是共享的...所以需要同步...诸如spinlock跟raise irql等等的东西就是因为这个而存在的...

以上


你看看windows 2000的源代码吧




你有吗?能给我一份吗?十分感谢
qwdrv
驱动大牛
驱动大牛
  • 注册日期2004-03-19
  • 最后登录2005-12-15
  • 粉丝0
  • 关注0
  • 积分8分
  • 威望2点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
11楼#
发布于:2004-10-29 08:02
这一类的高层驱动其实本身就是一个服务程序,所以不要想到什么单独开进程线程什么的
tiamo
VIP专家组
VIP专家组
  • 注册日期2002-02-26
  • 最后登录2018-01-09
  • 粉丝17
  • 关注4
  • 积分50分
  • 威望142点
  • 贡献值1点
  • 好评度40点
  • 原创分2分
  • 专家分15分
  • 原创先锋奖
  • 社区居民
12楼#
发布于:2004-10-28 23:52
这几个问题..你应该翻翻前面的帖子....

第一个问题显得很庞大...你可以到windows源码版看看我发的那个device tree的建立过程的帖子

第二个问题同上..同一篇文章里面有解释

第三个问题...有很多种情况..有一部分是在调用你的driver的线程环境里面执行的...如果你的driver调用了waitxx一类的函数..那么就发生了线程切换..到了另外的一个线程..当你waitxx一类函数条件满足的时候...又轮到你的函数执行...这个部分..并不会创建线程.具体的讲..就多了..涉及到线程切换..涉及到waitxx函数的实现..apc等等的东西...你看看windows 2000的源代码吧...有机会我也会准备一篇关于线程调度的文章出来...

第四个问题...驱动的代码确实只有一份..全局变量确实是放到nonpage memory上的(默认情况)..确实是共享的...所以需要同步...诸如spinlock跟raise irql等等的东西就是因为这个而存在的...

以上
RED_spring
驱动中牛
驱动中牛
  • 注册日期2002-07-28
  • 最后登录2016-11-06
  • 粉丝0
  • 关注0
  • 积分3分
  • 威望19点
  • 贡献值0点
  • 好评度17点
  • 原创分0分
  • 专家分0分
  • 社区居民
13楼#
发布于:2004-10-28 19:06
如果返回IO_PENDING,你说的可能性都存在。 有很多driver的就是这样工作的。
stoneyr
驱动牛犊
驱动牛犊
  • 注册日期2002-01-13
  • 最后登录2007-10-31
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
14楼#
发布于:2004-10-28 16:34
关于楼主的问题,偶的看法:(不保证正确哈 :cool:)

1:AddDevice通常是系统在发现新设备的时候,根据注册表中各设备与驱动的关联调用的。可以参考一下设备堆栈的形成过程。 象你说的那种没有任何原因,AddDevice就被调用的情况我还没发现。(不排除没有跟踪到哈~) 你是否可以举个例子? (注意你的设备类型和安装选项。比如说:UpFilter。。。)

2:我想Driver的载入顺序和安装时的启动选项有关吧?

3:和被调用的方式有关。 driver本身可以看做是内存中的一个模块,提供了一些接口。那个线程来调用它,它就处于那个线程的上下文。(这好像是句废话 :D) 系统调用的方式可以有很多种,看你driver的层次。有一种情况是可以肯定的,当你用DeviceIoControl与driver通信的时候,driver处于你的AP所处的上下文。(其实你可以做一些试验 :))

4:偶也不太清楚。 driver里的全局变量应该是唯一的。(互斥应该是须要的) dll(2k)里的某些数据段采用的是copy on write的机制。

这些东东偶也考虑过很久,很多没搞清楚。  


一个简单的例子就是如果你写一个驱动程序只有DriverEntry和AddDevice两个例程,正常安装后你就知道当安装好后,AddDevice已经被调用了。明显没有相应的硬件。
什么线程调用这些例程,则这些例程在该线程的上下文中运行,这个我可以理解,开始的时候我也是这样理解的,但是有一点我不是很明白,就是当你调用IoCallDriver时,如果返回IO_PENDING,那么这个IRP跑哪去了?传递下去后的处理会在哪个线程呢?因为前一个线程已经被调用IoCallDriver的函数终止并返回了。
现在我想大概是这样的,如果出现这种情况,操作系统会给这个IRP新开一个线程,到合适的时候会调入该线程来处理该IRP,因为那天我在书上看到IRP结构中有一个很重要的不可访问的域threadentries(好象是这么写的)。
RED_spring
驱动中牛
驱动中牛
  • 注册日期2002-07-28
  • 最后登录2016-11-06
  • 粉丝0
  • 关注0
  • 积分3分
  • 威望19点
  • 贡献值0点
  • 好评度17点
  • 原创分0分
  • 专家分0分
  • 社区居民
15楼#
发布于:2004-10-28 13:02
关于楼主的问题,偶的看法:(不保证正确哈 :cool:)

1:AddDevice通常是系统在发现新设备的时候,根据注册表中各设备与驱动的关联调用的。可以参考一下设备堆栈的形成过程。 象你说的那种没有任何原因,AddDevice就被调用的情况我还没发现。(不排除没有跟踪到哈~) 你是否可以举个例子? (注意你的设备类型和安装选项。比如说:UpFilter。。。)

2:我想Driver的载入顺序和安装时的启动选项有关吧?

3:和被调用的方式有关。 driver本身可以看做是内存中的一个模块,提供了一些接口。那个线程来调用它,它就处于那个线程的上下文。(这好像是句废话 :D) 系统调用的方式可以有很多种,看你driver的层次。有一种情况是可以肯定的,当你用DeviceIoControl与driver通信的时候,driver处于你的AP所处的上下文。(其实你可以做一些试验 :))

4:偶也不太清楚。 driver里的全局变量应该是唯一的。(互斥应该是须要的) dll(2k)里的某些数据段采用的是copy on write的机制。

这些东东偶也考虑过很久,很多没搞清楚。
RED_spring
驱动中牛
驱动中牛
  • 注册日期2002-07-28
  • 最后登录2016-11-06
  • 粉丝0
  • 关注0
  • 积分3分
  • 威望19点
  • 贡献值0点
  • 好评度17点
  • 原创分0分
  • 专家分0分
  • 社区居民
16楼#
发布于:2004-10-28 12:33
放在DeviceExtension里是不可分页的,而且你可以通过DISPATCH的DEVICEOBJECT来获得该地址,访问里面的东西,全局变量可以放在外面和RING3的一样,而且在X86下全局变量的东西本身也是不可分页.


wowocock:再请教一下,为什么X86下全局变量也是不可分页的? 看来偶汇编还是没学通  :P
ma_rui777
驱动牛犊
驱动牛犊
  • 注册日期2003-04-20
  • 最后登录2005-07-15
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
17楼#
发布于:2004-10-28 09:46
回答第三个问题:以下内容引用于《windows driver model》
"To understand when and how it’s permissible for a WDM driver to block a thread on a kernel dispatcher object, you have to recall some of the basic facts about threads from Chapter 2. In general, whatever thread was executing at the time of a software or hardware interrupt continues to be the current thread while the kernel processes the interrupt. We speak of executing kernel-mode code in the context of this current thread. In response to interrupts of various kinds, the scheduler might decide to switch threads, of course, in which case a new thread becomes “current.”

We use the terms arbitrary thread context and nonarbitrary thread context to describe the precision with which we can know the thread in whose context we’re currently operating in a driver subroutine. If we know that we’re in the context of the thread that initiated an I/O request, the context is not arbitrary. Much of the time, however, a WDM driver can’t know this fact because chance usually controls which thread is active when the interrupt occurs that results in the driver being called. When applications issue I/O requests, they cause a transition from user mode to kernel mode. The I/O Manager routines that create an IRP and send it to a driver dispatch routine continue to operate in this nonarbitrary thread context, as does the first dispatch routine to see the IRP. We use the term highest-level driver to describe the driver whose dispatch routine first receives the IRP.

As a general rule, only a highest-level driver can know for sure that it’s operating in a nonarbitrary thread context. Let’s suppose you are a dispatch routine in a lower-level driver, and you’re wondering whether you’re getting called in an arbitrary thread. If the highest-level driver just sent you an IRP directly from its dispatch routine, you’d be in the original, nonarbitrary, thread. But suppose that driver had put an IRP on a queue and then returned to the application. That driver would have removed the IRP from the queue in an arbitrary thread and then sent it or another IRP to you. Unless you know that didn’t happen, you should assume you’re in an arbitrary thread if you’re not the highest-level driver.

Notwithstanding what I just said, in many situations you can be sure of the thread context. Your DriverEntry and AddDevice routines are called in a system thread that you can block if you need to. You won’t often need to explicitly block inside these routines, but you could if you wanted to. You receive IRP_MJ_PNP requests in a system thread too. In many cases, you must block that thread to correctly process the request. Finally, you’ll sometimes receive I/O requests directly from an application, in which case you’ll know you’re in a thread belonging to the application.

"
stoneyr
驱动牛犊
驱动牛犊
  • 注册日期2002-01-13
  • 最后登录2007-10-31
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
18楼#
发布于:2004-10-23 22:12
还有一个问题:
总线驱动程序,是不是既作为该总线的功能驱动程序,又作为其所创建的每一个PDO的功能驱动程序?
也就是在系统加载总线驱动程序时,PNP管理器调用该总线驱动程序的AddDevice例程,这时它创建一个对应的FDO,总线驱动程序得以枚举接在其上的设备,当枚举到一个物理设备时,创建对应的PDO,并通知PNP管理器加载相应的功能驱动,这个功能驱动程序不管它下面的PDO,而是由总线驱动程序接管。
是不是这样?
stoneyr
驱动牛犊
驱动牛犊
  • 注册日期2002-01-13
  • 最后登录2007-10-31
  • 粉丝0
  • 关注0
  • 积分0分
  • 威望0点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
19楼#
发布于:2004-10-23 21:06
怎么理解“随机的进程”?
随机是不是就是说无进程?还是怎么回事?Windows不会随便中止一个进程然后就执行驱动程序,那一个系统这么驱动程序,任意一个随时都可能会终止了?
上一页
游客

返回顶部