中断请求级别

时间:2021-11-20 19:36:11

Windows有两种中断请求(IRQ, INTERRUPT REQUEST),一种是外部中断,也就是硬件中断,另外一种是软件中断,比如常用的INT 3下个断点。

现在的x86计算机基本都是用高级可编程控制器(Advanced Programmable Interrupt Controller, 简称APIC)来控制IRQ。正在运行的线程可以随时被中断打断,进入到中断处理程序。优先级高的中断可以打断优先级低的中断处理程序,进入更高级别的中断处理函数。APIC中总共有24个IRQ。

IRQL(INTERRUPT REQUEST LEVEL)

Windows将中断的概念进行了扩展,提出一个中断请求级(IRQL)的概念。其中规定了32个中断请求级别,分别是:

0 - 2级为软件中断

3 - 31级为硬件中断(包括APIC的24个中断)

如图(图片来自于《windows驱动开发技术详解》):

                                     中断请求级别

Windows大部分时间都运行在软件中断级别中,即0-2级别。当有设备中断来临时,windows会将IRQL提升至硬件中断级别(DIRQL, DEVICE INTERRUPT REQUEST LEVEL),并且运行相应的硬件中断处理函数。当硬件中断结束后,恢复到原来的IRQL。

用户模式的代码是运行在最低级别的PASSIVE_LEVEL中,驱动程序的DriverEntry函数,派遣函数,AddDevice函数一般运行在PASSIVE_LEVEL中(驱动程序的StartIO和DPC函数运行在DISPATCH_LEVEL中),它们在必要的时候可以申请进入DISPATCH_LEVEL级别,使用内核函数KeGetCurrentIrql()可以知道系统的当前IRQL。

Windows负责线程调度的组件运行在DISPATCH_LEVEL级别,当前线程运行完时间片后,操作系统自动从PASSIVE_LEVEL提升至DISPATCH_LEVEL级别,从而可以使得线程调度组件可以调度其他的线程。当线程切换完成后,操作系统又从DISPATCH_LEVEL级别恢复到PASSIVE_LEVEL级别。

线程优先级

线程优先级不同于IRQL,应用程度在PASSIVE_LEVEL运行的时候,程序员可以设定线程优先级(可以使用API SetThreadPriority)。优先级高代表可以有更多机会在CPU上运行。当线程调度内核组件运行于DISPATCH_LEVEL的时候,所有应用程序的线程都停止,等着被调度。

 

IRQL和分页内存(虚拟内存)

Windows支持虚拟内存,当有需要的时候windows会将物理内存上暂时不用的数据交换到虚拟内存以腾出内存空间给其他应用使用。当应用程序需要这些数据的时候,由于这些数据不在物理内存上,那么就会产生一个页故障,页故障的异常处理函数会将虚拟内存上相关的数据交换到物理内存,这样应用程序就可以读取数据了。页故障运许出现在PASSIVE_LEVEL级别的程序中,但如果出现在DISPATCH_LEVEL或者更高级别的程序中会带来崩溃。

所以,对于高于或者等于DISPATCH_LEVEL级别的程序不能使用分页内存,必须使用非分页内存,不然就是崩溃(比如驱动程序的StartIO,DPC函数中,千万不要使用分页内存,不然就死翘翘了)。

 

控制IRQL提升和降低

通过几个内核函数可以读取,提升或者降低当前IRQL。分别是:KeGetCurrentIrql, KeRaiseIrql和KeLowerIrql。

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

IRQL

   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大大减少。
   DIRQL (Device IRQL)
  一般的,更高级的驱动在这个级别上不处理IRQL,但是几乎所有的中断被屏蔽,这实际上是IRQL的一个范围,这是一个决定某个驱动有更高的优先级的方法。