阅读:6320回复:27
关于WDM驱动程序的一些问题,想了很久都没有想通,特来此问
1、系统检测到硬件时调用AddDevice例程让驱动程序增加一个硬件设备,但是如果创建的驱动程序并不针
对任何一个硬件,那这个AddDevice例程是什么时候被调用的呢?系统为什么要调用这个例程呢?比如一 个只有DriverEntry和AddDevice两个函数的驱动程序,同样也可以正常编译,正常安装,安装好后却发现 系统也正常调用了AddDevice例程。 2、WDM驱动程序在AddDevice里创建了一个设备,并注册了设备接口,其目的是为了给上层应用程序提供 访问该设备的接口。那就说在上层应用程序使用这个设备之前,这个驱动程序早就已经被装载,并且系统 已经调用了其AddDevice例程,要不然的话上层应用程序就没有设备接口可用了。那这个驱动程序是在什 么时候被装载的?在操作系统启动的时候?还是......?在INF文件里有一个控制驱动装载的选项,有一 个值是在系统需要的时候装载该驱动,但是什么时候才是系统需要的时候呢? 3、驱动程序里的各个例程,是运行在与上层应用相同的线程上下文环境,还是操作系统内核另外开一个 线程来执行该例程?如果是前者,那么驱动程序是如果实现对IRP的延迟处理的,因为如果延迟了,那上 层应用中线程不是也被阻塞了吗?如果是后者,操作系统对每一个活动的例程都要开一个线程,那不是要 占用系统很多的资源,这样为什么不会影响系统的性能? 4、驱动程序的代码在整个系统中是不是只有一份?也就是说如果驱动程序里有一个全局变量,那么访问 该全局变量的所有例程都就应该同步或互斥,而不象dll(Win2K)中的全局变量,即使是全局变量如果不 声明在共享数据段内都不是共享的。 |
|
沙发#
发布于:2004-10-16 09:19
顶,我和你一样。
|
|
板凳#
发布于:2004-10-16 11:18
怎么没有人关注?
神呀,帮帮我吧。 |
|
地板#
发布于:2004-10-16 12:58
1.2:我的理解是:驱动程序在启动时(注册表中services中的start决定操作系统何时启动驱动程序,也可以在用户程序调用setup*函数启动驱动程序),支持完全PNP的驱动会由PNP管理器自动调用位于DeviceObject->DeviceExtension->AddDevice函数。对于非完全PNP驱动,AddDevice的功能在DriverEntry中实现。所以可以看到在很多NT驱动程序中并没有AddDevice函数。
3:我想是前者,但这个问题弄的不是很透彻,哪位出来说说? 4:一般是这样的,通常驱动所用的全局变量放在DevcieExtension中,而且必须同步操作。 |
|
地下室#
发布于:2004-10-17 10:09
1.2:我的理解是:驱动程序在启动时(注册表中services中的start决定操作系统何时启动驱动程序,也可以在用户程序调用setup*函数启动驱动程序),支持完全PNP的驱动会由PNP管理器自动调用位于DeviceObject->DeviceExtension->AddDevice函数。对于非完全PNP驱动,AddDevice的功能在DriverEntry中实现。所以可以看到在很多NT驱动程序中并没有AddDevice函数。 如果如你所说,PNP管理器在调用AddDevice时,其参数中的PDO应该是指向什么设备对象呢? 如果全局变量放在DeviceExtension里,对于同一个驱动程序管理下的不同的设备,会有不同的值。如果需要它们具有相同的值的话,那是不是应该放在外面呢?对于声明为static的变量是不是对不同的设备具有相同的值呢? |
|
5楼#
发布于:2004-10-18 09:15
放在DeviceExtension里是不可分页的,而且你可以通过DISPATCH的DEVICEOBJECT来获得该地址,访问里面的东西,全局变量可以放在外面和RING3的一样,而且在X86下全局变量的东西本身也是不可分页.
|
|
|
6楼#
发布于:2004-10-18 14:55
建议搂主仔细的看看ddk的toaster例子(包括function driver和bus driver)
如果你把这个例子搞懂了,就不会再问上边的问题了。 |
|
7楼#
发布于:2004-10-18 19:55
建议搂主仔细的看看ddk的toaster例子(包括function driver和bus driver) 好,仔细看看。 |
|
8楼#
发布于:2004-10-19 00:48
1。对于软的驱动程序来说,虽然它并不针对任何一个硬件,但是系统会在安装的时候创建相应的设备节点(ROOT Bus devnode, under HKLM\System\CurrentControlSet\Enum\Root\Legacy_xxx)。在系统启动时,将会生成PDO并调用AddDevice。请参考Walter Oney "Programming The Windows Driver Model"第二章。
2。 (1) 那这个驱动程序是在什么时候被装载的? 请参考CreateService (2)但是什么时候才是系统需要的时候呢? Net start XXX / StartService 3。都不是。是在随机的进程中,不要认为Driver会运行在自己的进程中。上面的进程会不会被阻塞取决于你用的是同步还是异步操作。 请参考Overlapped IO (paramenter lpOverlapped) of ReadFile and DeviceIoControl. 4。驱动程序的代码在整个系统中只有一份,但是对于每一个PDO都有一个对应的DeviceExtension,因为每个设备实例都会调用AddDevice,并创建一份DeviceExtension,可以想象成C++的实例化。全局变量将会被共享 |
|
9楼#
发布于:2004-10-23 21:06
怎么理解“随机的进程”?
随机是不是就是说无进程?还是怎么回事?Windows不会随便中止一个进程然后就执行驱动程序,那一个系统这么驱动程序,任意一个随时都可能会终止了? |
|
10楼#
发布于:2004-10-23 22:12
还有一个问题:
总线驱动程序,是不是既作为该总线的功能驱动程序,又作为其所创建的每一个PDO的功能驱动程序? 也就是在系统加载总线驱动程序时,PNP管理器调用该总线驱动程序的AddDevice例程,这时它创建一个对应的FDO,总线驱动程序得以枚举接在其上的设备,当枚举到一个物理设备时,创建对应的PDO,并通知PNP管理器加载相应的功能驱动,这个功能驱动程序不管它下面的PDO,而是由总线驱动程序接管。 是不是这样? |
|
11楼#
发布于: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. " |
|
12楼#
发布于:2004-10-28 12:33
放在DeviceExtension里是不可分页的,而且你可以通过DISPATCH的DEVICEOBJECT来获得该地址,访问里面的东西,全局变量可以放在外面和RING3的一样,而且在X86下全局变量的东西本身也是不可分页. wowocock:再请教一下,为什么X86下全局变量也是不可分页的? 看来偶汇编还是没学通 :P |
|
13楼#
发布于: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的机制。 这些东东偶也考虑过很久,很多没搞清楚。 |
|
14楼#
发布于:2004-10-28 16:34
关于楼主的问题,偶的看法:(不保证正确哈 :cool:) 一个简单的例子就是如果你写一个驱动程序只有DriverEntry和AddDevice两个例程,正常安装后你就知道当安装好后,AddDevice已经被调用了。明显没有相应的硬件。 什么线程调用这些例程,则这些例程在该线程的上下文中运行,这个我可以理解,开始的时候我也是这样理解的,但是有一点我不是很明白,就是当你调用IoCallDriver时,如果返回IO_PENDING,那么这个IRP跑哪去了?传递下去后的处理会在哪个线程呢?因为前一个线程已经被调用IoCallDriver的函数终止并返回了。 现在我想大概是这样的,如果出现这种情况,操作系统会给这个IRP新开一个线程,到合适的时候会调入该线程来处理该IRP,因为那天我在书上看到IRP结构中有一个很重要的不可访问的域threadentries(好象是这么写的)。 |
|
15楼#
发布于:2004-10-28 19:06
如果返回IO_PENDING,你说的可能性都存在。 有很多driver的就是这样工作的。
|
|
16楼#
发布于:2004-10-28 23:52
这几个问题..你应该翻翻前面的帖子....
第一个问题显得很庞大...你可以到windows源码版看看我发的那个device tree的建立过程的帖子 第二个问题同上..同一篇文章里面有解释 第三个问题...有很多种情况..有一部分是在调用你的driver的线程环境里面执行的...如果你的driver调用了waitxx一类的函数..那么就发生了线程切换..到了另外的一个线程..当你waitxx一类函数条件满足的时候...又轮到你的函数执行...这个部分..并不会创建线程.具体的讲..就多了..涉及到线程切换..涉及到waitxx函数的实现..apc等等的东西...你看看windows 2000的源代码吧...有机会我也会准备一篇关于线程调度的文章出来... 第四个问题...驱动的代码确实只有一份..全局变量确实是放到nonpage memory上的(默认情况)..确实是共享的...所以需要同步...诸如spinlock跟raise irql等等的东西就是因为这个而存在的... 以上 |
|
17楼#
发布于:2004-10-29 08:02
这一类的高层驱动其实本身就是一个服务程序,所以不要想到什么单独开进程线程什么的
|
|
18楼#
发布于:2005-03-21 13:24
这几个问题..你应该翻翻前面的帖子.... 你看看windows 2000的源代码吧 你有吗?能给我一份吗?十分感谢 |
|
19楼#
发布于:2005-03-22 09:36
我的理解:
1.无硬件的AddDevice: 是inf安装时写入了注册表:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Class里实现的.Windows会读这个,实现AddDevice 2.inf文件指定的 3.驱动是系统自己开的线程.驱动里也可以开别的线程,特别是在处理PASSIVE_LEVEL上的函数时,有时非开线程不可 4.全局变量是唯一的,一定要加互斥保护 |
|
上一页
下一页