分页内存与非分页内存导致的蓝屏死机问题
windows驱动开发中,感觉很多小问题都会导致一些比较麻烦的错误,很多不良习惯都可能会导致系统崩溃。原因是对内核原理的理解太欠缺了,因为驱动运行在RING0优先级,开发的时候必须相当注意细节,不然调试的时候会很麻烦(有些时候Dump文件分析出来是错误的)。原来我一直奇怪写驱动程序问什么要把有些例程放到非分页内存中,今天算是豁然开朗。只怪原来看内核原理的时候没太仔细。具体原因是这样的:因为windows的缺页中断处理程序是运行在DISPATCH_LEVEL的级别的。而我的驱动某些例程一般是等于DISPATCH_LEVEL这个中断级别。也就是说。。如果我把我的代码放到分页内存中。。那操作系统很可能在某个时候就把它从物理内存换出到磁盘页面交换文件中了。。然后EIP指针如果访问到的下一个内存页在换页文件中。。那操作系统将产生缺页中断。。然后这缺页中断的级别与我的代码例程是一个级别的。。所以不能被打断。。EIP就会访问的一个错误的内存地址(很可能读/写到了其他进程,也可能是系统中重要的数据)上,,用户层的程序内存访问违例的异常操作系统能捕捉到。反馈给用户。。。而在驱动内核层内存访问错误。。这是一个很严重的问题。。操作系统发现立即就以蓝屏的方式处理了。。严重的还导致系统崩溃。就悲剧了。。。另外还有一点就是OS的线程调度程序也运行在这个级别。。这也应该有意识。。不然引起线程切换导致蓝屏也时常发生。。。。。。。。
TIPS:
DISPATCH > APC > PASSIVE
IRQL是Interrupt ReQuest Level,中断请求级别。一个由windows虚拟出来的概念,划分在windows下中断的优先级,这里中断包括了硬中断和软中断,硬中断是由硬件产生,而软中断则是完全虚拟出来的。
处理器在一个IRQL上执行线程代码。IRQL是帮助决定线程如何被中断的。在同一处理器上,线程只能被更高级别IRQL的线程能中断。每个处理器都有自己的中断IRQL。
我们在调用NDIS API时,在DDK帮助文档中都有该API函数的所在级别。
PASSIVE_LEVEL
IRQL最低级别,没有被屏蔽的中断,在这个级别上,线程执行用户模式,可以访问分页内存。
APC_LEVEL
在这个级别上,只有APC级别的中断被屏蔽,可以访问分页内存。当有APC发生时,处理器提升到APC级别,这样,就屏蔽掉其它APC,为了和APC执行一些同步,驱动程序可以手动提升到这个级别。比如,如果提升到这个级别,APC就不能调用。在这个级别,APC被禁止了,导致禁止一些I/O完成APC,所以有一些API不能调用。
DISPATCH_LEVEL
这个级别,DPC 和更低的中断被屏蔽,不能访问分页内存,所有的被访问的内存不能分页。因为只能处理非分页内存,所以在这个级别,能够访问的Api大大减少。