irql

处理器在一个IRQL上执行线程代码。IRQL是帮助决定线程如何被中断的。在同一处理器上,线程只能被更高级别IRQL的线程能中断。每个处理器都有自己的中断IRQL。常见的IRQL级别有四个:Passive、APC、 Dispatch、DIRQL。

 

PASSIVE_LEVEL
IRQL最低级别,没有被屏蔽的中断,线程执行用户模式,可以访问分页内存。

APC_LEVEL
只有APC级别的中断被屏蔽,可以访问分页内存。当有APC发生时,处理器提升到APC级别,这样,就屏蔽掉其它APC,为了和APC执行 一些同步,驱动程序可以手动提升到这个级别。比如,如果提升到这个级别,APC就不能调用。在这个级别,APC被禁止了,导致禁止一些I/O完成APC, 所以有一些API不能调用。

DISPATCH_LEVEL
DPC(延迟过程) 和更低的中断被屏蔽,不能访问分页内存,所有的被访问的内存不能分页。因为只能处理分页内存,所以在这个级别,能够访问的API大大减少。
KeLowerIrql与KeRaiseIrql
可以先提升IRQL,然后恢复(下降)到原有IRQL;不能单独调用KeLowerIrql来降低IRQL;调用了KeRaiseIrql后必须调用KeLowerIrql恢复原有IRQL。
 
 

PAGED_CODE这个宏可以确保调用线程运行在一个允许分页的足够低IRQL级别。

参数:无

返回值:无

注释:如果IRQL > APC_LEVEL,则PAGED_CODE()会对系统产生一个断言。
对这个宏的调用必须放在一个包含有可以使用分页内存的代码或者访问分页内存的代码的驱动例程的开始位置。
PAGED_CODE这个宏仅仅检测这个宏所在位置的IRQL级别。如果在这个宏之后提升IRQL级别,PAGED_CODE将无法检测出之后的IRQL级别。当IRQL被不适当的提升的时候驱动程序员必须使用其他函数来检测IRQL级别。
 IRQL>APC,则是DPC; 该level下只能访问非分页内存,因此PAGED_CODE会产生断言错误:
#if DBG
#define PAGED_CODE() { \
 if (KeGetCurrentIrql() > APC_LEVEL) { \
  KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
  ASSERT(FALSE); \
 } \
}
#else
#define PAGED_CODE() NOP_FUNCTION;
#endif
 IRQL>APC,则是DPC; 该level下只能访问非分页内存,因此PAGED_CODE会产生断言错误:
#if DBG
#define PAGED_CODE() { \
 if (KeGetCurrentIrql() > APC_LEVEL) { \
  KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
  ASSERT(FALSE); \
 } \
}
#else
#define PAGED_CODE() NOP_FUNCTION;
#endif
 IRQL>APC,则是DPC; 该level下只能访问非分页内存,因此PAGED_CODE会产生断言错误:
#if DBG
#define PAGED_CODE() { \
 if (KeGetCurrentIrql() > APC_LEVEL) { \
  KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
  ASSERT(FALSE); \
 } \
}
#else
#define PAGED_CODE() NOP_FUNCTION;
#endif
 IRQL>APC,则是DPC; 该level下只能访问非分页内存,因此PAGED_CODE会产生断言错误:
#if DBG
#define PAGED_CODE() { \
 if (KeGetCurrentIrql() > APC_LEVEL) { \
  KdPrint(( "EX: Pageable code called at IRQL %d\n", KeGetCurrentIrql() )); \
  ASSERT(FALSE); \
 } \
}
#else
#define PAGED_CODE() NOP_FUNCTION;
#endif

 

 

 

 

 

默认情况下,内核加载器会加载所有的代码部分和全局数据到非分页内存中。而且,加载器是一次加载整个驱动的可执行文件,包括相关的DLL。加载后,内核加载器关闭驱动程序文件,甚至你可以删除当前正在执行的驱动文件。
但是,你可以告诉加载器你希望驱动的哪部分是可分页,所谓可分页,就是可能会被换页出内存(Page out)

分页内存是虚拟内存,在物理上未必总是能得到。

操作系统实现虚拟内存的主要方法就是通过分页机制。在Win32中,物理地址空间,二维虚拟地址空间和实际内存地址是三个不同的概念。操作系统通过段选择子构成二维虚拟地址空间,每个进程有一个4G的地址空间,然后操作系统的内存管理器件把每个进程映射到一维物理地址空间的不同部分,但是因为我们实际机器上大都没有4G内存,所以,实际内存空间是物理地址空间的子集。

分页管理器把地址空间划分成4K大小的页面(非IntelX86体系与之不同),当进程访问某个页面时,操作系统首先在Cache中查找页面,如果该页面不在内存中,则产生一个缺页中断(PageFault),进程就会被阻塞,直至要访问的页面从外存调入内存中。
我们知道,在处理低优先级的中断时,仍可以发生高优先级的中断。既然缺页过程也是一个中断过程,那么就产生一个问题,即,缺页中断和其他中断的优先级的问题。如果在高于缺页中断的中断优先级上再发生缺页中断,内核就会崩溃。所以在DISPATCH_LEVEL级别以上,绝对不能使用分页内存,一旦使用分页内存,就有发生缺页中断的可能,前面说过,这样会导致内核崩溃。


简单来说就是,如果你写的驱动级别比较高,或者就是硬件驱动,代码必须一直在内存中,就不用特别声明。

如果你觉得部分函数可以被从内存中转换到硬件临时文件中,也不会影响程序运行就可以声明是分页的。

 

=====================================================================================

分页内存运行在较低的IRQL; 非分页内存运行在较高的IRQL。

当在较高的IRQL运行的线程产生一个缺页中断, 将导致蓝屏。 【【缺页, 也是一个irq】】

较低级别的irq可以被高级别的irq中断; 高级别的irq运行中不允许低级别的irq。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值