在设计windows的时候,设计者将中断请求划分为软件中断和硬件中断,并将这些中断都映射成不同级别的中断请求级(IRQL),同步处理机制很大程度上依赖于中断请求级。
中断请求(IRQ)一般有两种:外部中断,即硬件产生的中断;由软件指令int n产生的中断。windows将中断的概念进行了扩展,提出了中断请求级(IRQL)的概念。其中规定了32个中断请求级别,分别是0~2级别为软件中断,3~31级为硬件中断,数字从0到31,优先级别逐次递增。硬件的IRQL称为设备中断请求级,或者简称DIRQL。windows大部分时间运行在软件中断级别中,当设备中断来临时,操作系统提升IRQL至DIRQL级别,并且运行中断处理函数。当中断处理函数结束后,操作系统把IRQL降到原来的级别。
用户模式的代码、驱动程序的DriverEntry函数、派遣函数、AddDevice等函数一般都运行在PASSIVE_LEVEL级别,它们在必要时可以申请进入DISPATCH_LEVEL级别。
在内核模式下,可以通过调用KeGetCurrentIrql内核函数来得到当前的IRQL级别;内核函数KeRaiseIrql可将IRQL提高,KeRaiseIrql需要两个参数,分别是:提升后的IRQL级别和保存提升前的IRQL级别;如果需要恢复到以前的IRQL级别,则可以调用KeLowerIrql内核函数,如:
VOID RaiseIRQL_Test()
{
KIRQL oldirql;
ASSERT(KeGetCurrentIrql()<= DISPATCH_LEVEL); //确保当前IRQL等于或小于DISPATCH_LEVEL
KeRaiseIrql(DISPATCH_LEVEL,&oldirql); //提升IRQL至DISPATCH_LEVEL并保存之前的IRQL
KeLowerIrql(oldirql); //恢复到之前的IRQL
}
IRQL与内存分页:
分页内存随时可能从物理内存交换到磁盘文件,读取不在物理内存中的分页内存时,会引发一个页故障,从而执行这个异常的处理函数,异常处理函数会重新将磁盘文件的内容交换到物理内存中。
页故障允许出现在PASSIVE_LEVEL级别的程序中,但如果在DISPATCH_LEVEL或者更高级别IRQL的程序中会带来系统崩溃。
对于等于或者高于DISPATCH_LEVEL级别的程序不能使用分页内存,必须使用非分页内存。驱动程序的StartIOS例程、DPC例程、中断服务例程都运行在DISPATCH_LEVEL或者更高的IRQL。因此,这些例程中不能使用分页内存,否则会导致系统崩溃。