中断请求级别

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的一个范围,这是一个决定某个驱动有更高的优先级的方法。

### ARM 架构中断优先级别概述 在 ARM Cortex-M 处理器中,异常是否能被处理器接受以及何时被执行取决于异常的优先级和处理器当前的状态[^1]。具体来说: - **固定优先级**:某些特定类型的异常(如复位、NMI 和 HardFault)拥有固定的最高优先级,并且这些优先级通过负数值表示。 - **可配置优先级**:大多数其他异常允许设定一个介于 0 到 255 范围内的可编程优先级。 ### NVIC 中断控制器的角色 为了实现更加精细的控制,Nested Vectored Interrupt Controller (NVIC) 提供了两种不同类型的优先级设置——抢占优先级(preemption priority)和响应优先级(subpriority)[^2]。这意味着每个中断源都可以独立指定这两个参数之一或两者皆有: - 当多个中断请求同时到来时,系统首先依据抢占优先级来进行判断;如果存在相等的情况,则进一步考虑响应优先级。 - 较高的抢占优先级可以打断较低者正在运行的服务例程;然而,在同等条件下,即使某一方具备更高的响应等级也不能中途插队执行。 ### 实际操作中的应用实例 下面是一个简单的例子展示如何利用 CMSIS 库函数来调整 STM32 微控制器上的外部线中断 EXTI9_5 的优先级: ```c #include "stm32f4xx_hal.h" int main(void){ HAL_Init(); // 初始化系统时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); // 开启 GPIOA 时钟 /* 配置 PA0 作为输入 */ GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_0; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING; // 上升沿触发中断 GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 设置 EXTI9_5 中断优先级为最低(7),其中抢占优先级设为3,子优先级也设为3 HAL_NVIC_SetPriority(EXTI9_5_IRQn, 7 >> 4 , 7 & 0xf); // 启用该中断通道 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); while (1){} } ``` 此代码片段展示了如何初始化硬件资源并将某个外设产生的事件映射到相应的 IRQ 线路上去,同时还指定了具体的优先权分配方案以便更好地管理和调度多任务环境下的异步信号流。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值