IRQL 中断请求级别

selph
selph
发布于 2021-09-08 / 1024 阅读
0
0

IRQL 中断请求级别

IRQL 是 Windows 给 CPU 的一种机制,不会被等级小于等于当前 IRQL 的中断请求而中断,以达到同步处理的需要。

IRQL 简介

IRQL 中断请求级别是操作系统赋予 CPU 的一种机制,不是来自 CPU 的,是 Windows 系统上最重要的性能机制之一。

中断请求 IRQ 一般有两种,一种是外部中断(硬件产生的中断),另一种是软件中断(Int 3 断点中断,int 1 单步中断等),后来 Windows 操作系统将中断进行了扩展,提出了中断请求级的概念,其中规定了 32 个中断请求级别,分别是 0-2 级别为软件中断,3-31 为硬件中断。

驱动编程中通常接触到的是 0 到 2 的 IRQL 以及 DIRQL:

IRQLIRQL 数值:x86IRQL 数值:AMD64IRQL 数值:IA64描述
Passive Level000应用层线程和大部分内核函数处于该 IRQL,可以无限制使用所有内核 API,可以访问分页以及分分页内存
APC Level111异步方法调用(APC)或页错误时处于该 IRQL,可以使用大部分内核 API,可以访问分页以及分分页内存
Dispatch Level222延迟方法调用(DPC)时处于该 IRQL,可以使用特定的内存 API,只能访问非分页内存

如果某个中断产生了,如果中断级别比当前 IRQL 低,那么该中断不会影响当前程序运行,如果中断的 IRQL 比当前 CPU 的 IRQL 大,则会中断当前的中断

可通过 KeGetCurrentIRQL() 获取当前 IRQL 等级

说明:如果要共享数据,那么所有对该数据存取的活动都要安排在高于 PASSIVE_LEVEL 的同一个 IRQL 上。这样,在单 CPU 环境下,就能有效地避免共享冲突。

IRQL 的提升与降低

有些时候驱动程序中需要提升 IRQL 级别,在运行一段时间后,再将降回原来的 IRQL 级别,这样做的目的一般是基于同步处理的需要。

然后驱动程序使用内核函数 KeRaiseIrql 将 IRQL 提高。

KeRaiseIrql 需要两个参数,第一个数是提升后的 IRQL 级别,第二个参数是保存提升前的 IRQL 级别。

最后,驱动程序某个时刻需要将 IRQL 恢复到以前的 IRQL 级别,驱动程序可以调用 KeLowerIrql 内核函数。

下面代码演示了驱动中如何提升和降低 IRQL 的代码:

VOID RaiseIRQL_Test()
{
KIRQL oldirql;
// 确保当前 IRQL 等于或小于 DISPATCH_LEVEL
ASSERT(KeGetCurrentIrql() <= DIPATCH_LEVEL);
// 提升 IRQL 到 DISPATCH_LEVEL,并将先前的 IRQL 保存起来
KeRaiseIrql(DISPATCH_LEVEL, &oldirql);
//...
// 恢复到先前的 IRQL
KeLowerIrql(oldirql);
}

分页内存和非分页内存

Windows 操作系统定制了两种内存:

  • 分页内存:可以置换到硬盘上
  • 非分页内存:不能置换到硬盘上

调用 API 访问内存发生错误一般是 IRQL 出现错误了

要注意,DisPatch_Level(DPC_Level) 只能用非分页内存(错误 0x0000007E),因为在这个 IRQL 下,发生缺页中断的时候,因为缺页中断等级相同而不会进行触发,导致读取地址内容不在内存中,无法从硬盘置换出来,从而导致蓝屏

数值越低,优先级越低:DPC>APC> 大部分 API

参考资料:

IRQL 的理解和认识_`Nobody 的博客-CSDN 博客_irql

IRQL 深入解析--IRQL 级别_首席技术总监的专栏-CSDN 博客_irql

分页内存和非分页内存区别 - chanchaw - 博客园 (cnblogs.com)

IRQL 的理解和认识_`Nobody 的博客-CSDN 博客_irql


评论