IRQ,INTERRUPTREQUEST中断请求级别

更新时间:2023-05-12 13:17:17 阅读: 评论:0

IRQ,INTERRUPTREQUEST中断请求级别
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, KeRaiIrql和KeLowerIrql。
--------------------- ------------------------------------------
什么是IRQL?
IRQL是Interrupt ReQuest Level,中断请求级别。处理器在⼀个IRQL上执⾏线程代码。IRQL是帮助决定线程如何被中断的。在同⼀处理器上,线程只能被更⾼级别IRQL的线程能中断。每个处理器都有⾃⼰的中断IRQL。
我们经常遇见的有四种IRQL级别。“Passive”, “APC”, “Dispatch” and “DIRQL”.
“DriverEntry”将会在PASSIVE_LEVEL被调⽤。
#define PASSIVE_LEVEL                            0
#define LOW_LEVEL                                0
#define APC_LEVEL                                  1
#define DISPATCH_LEVEL                          2
#define PROFILE_LEVEL                            27
#define CLOCK1_LEVEL                            28
#define CLOCK2_LEVEL                            28
#define IPI_LEVEL                                  29
#define POWER_LEVEL                            30
#define HIGH_LEVEL                                31
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的最⾼等级。通常使⽤这个来判断设备的优先级。
⼀般的,更⾼级的驱动在这个级别上不处理IRQL,但是⼏乎所有的中断被屏蔽,这实际上是IRQL的⼀个范围,这是⼀个决定某个驱动有更⾼的优先级的⽅法。
1.3.1 内核代码运⾏级别
Windows NT为它的内核模式的代码分配了不同的级别。在同⼀个CPU上,级别低的过程
可以被任何级别更⼤的过程中断。级别由低到⾼排列如下:
级别名称 运⾏于该级别的过程
PASSIVE_LEVEL DriverEntry, Unload, ShutDown, DispatchXxx。
APC_LEVEL 在某些特殊情况下,⼤存储量设备的驱动程序运⾏于该级别。
DISPATCH_LEVEL StartIo, AdapterControl, ControllerControl, IoTimer,Dpc。
DIRQLs 各种中断处理程序。
表16.1 驱动程序例程的缺省IRQL
IRQL(由低到⾼) 屏蔽掉的中断  运⾏在此IRQL的⽀持例程
PASSIVE_LEVEL    ⽆        Dispatch、DriverEntry、AddDevice、Reinitialize、Unload例程、驱动程序创建的线程、⼯作者线程(work-thread)回调、⽂件系统驱动程序
DISPATCH_LEVEL  DISPATCH_LEVEL和APC_LEVEL中断被屏蔽掉了。设备、时钟和电源错误中断仍可发⽣
StartIo、AdapterControl、AdapterListControl、ControllerControl、IoTimer、Cancel(持有撤消⾃旋锁时)、DpcForIsr、CustomTimerDpc、CustomDpc例程
DIRQL  驱动程序中断对象中所有IRQL<=DIRQL的中断。时钟和电源错误中断仍可发⽣ ISR、SyncCritSection例程
  对于⾼层驱动程序可能需要⼀个或多个IoCompletion例程,最起码完成检查I/O状态块然后调⽤IoCompleteRequest的⼯作。如果需要,还要对Device Extension数据结构和内容做些修改。有⼀点必须很清楚的,就是代码运⾏级别的问题,即IRQL,最常见的级别是PASSIVE_LEVEL、APC_LEVEL、DISPATCH_LEVEL和DIRQL。
  在看NT DDK HELP中的函数说明的时候,要注意函数的可运⾏级别,⽐如有的函数只能在PASSIVE_LEVEL下运⾏,有的函数则可以在DISPATCH_LEVEL以下级别运⾏,级别越⾼的时候,对代码的要求就越严格,⽐如在DISPATCH_LEVEL的时候,就不能使⽤分页内存。通常情况下应该尽可能让代码在低运⾏级别如PASSIVE_LEVEL下运⾏,在⾼级别下运⾏过长时间将导致系统效率降低、影响系统响应的实时性。但有时候⾃⼰⽆法控制运⾏的级别,例如在调⽤低层Driver时使⽤IoCall
Driver,低层Driver响应完毕后会执⾏completion例程,该例程运⾏的级别就是由低层Driver来决定。因此在编写completion例程时,应尽量将这个函数设计成能在DISPATCH_LEVEL级别运⾏。
这篇⽂章主要说明俩个问题:
1. 在APC_LEVEL上,Thread为何不能被suspend。
2. 在 APC_LEVEL上,可以使⽤分页内存的原因。
关于线程如何响应APC,要看是何种APC,请参考MSDN⽂档。我在看微软提供的资料的时候,发现俩个⽐较难懂的问题,把它们单独拿出来讨论。
⾸先看中断请求级:IRQL(Interrupt Request Levels)
IRQL IRQL value
Description x86  IA64 AMD64
PASSIVE_LEVEL 0 0 0 Ur threads and most kernel-mode operations
APC_LEVEL    1    1    1 Asynchronous procedure calls and page faults DISPATCH_LEVEL    2    2   
2 Thread scheduler and deferred procedure calls (DPCs) CMC_LEVEL N/A    3 N/A Correctable machine-check level (IA64 platforms only)
Device interrupt levels (DIRQL) 3-26
4-
11
3-11 Device interrupts
PC_LEVEL N/A 12 N/A Performance counter (IA64 platforms only)
PROFILE_LEVEL 27 15 15 Profiling timer for releas earlier than Windows 2000
SYNCH_LEVEL 271313Synchronization of code and instruction streams across processors CLOCK_LEVEL N/A 13 13 Clock timer
CLOCK2_LEVEL 28 N/A N/A Clock timer for x86 hardware
IPI_LEVEL 29 14 14 Interprocessor interrupt for enforcing cache consistency
POWER_LEVEL 30 15 14 Power failure
HIGH_LEVEL 3115 15 Machine checks and catastrophic errors; profiling timer for Windows XP and later releas
微软说:
When a processor is running at a given IRQL, interrupts at that IRQL and lower are masked off (blocked) on the processor.
但其实这句话只适合在DISPATCH_LEVEL到HIGH_LEVEL之间。在APC_LEVEL和PASSIVE_LEVEL级别要特殊对待。⽽且这两个级别可以被调度器调度,就显得更加复杂。
所以微软⼜说:
IRQL分为: Processor-specific and Thread-specific IRQLs
Processor-specific IRQLS:
DISPATCH_LEVEL
DIRQL
HIGHEST_LEVEL
规则:When a processor is running at a given IRQL, interrupts at that IRQL and lower are masked off (blocked) on the processor.
Thread-specific IRQLS:
PASSIVE_LEVEL
IRQL PASSIVE_LEVEL in a critical region. Intermediate level(KeEnterCriticalRegion, KeLeaveCriticalRegion)
APC_LEVEL
在这三个级别上运⾏的线程,都能被调度器调度(调度器运⾏在DISPATCH_LEVEL),调度器考虑的只是优先级,优先级⾼的就能抢占优先级低的线程。所⼀个运⾏在APC_LEVEL低优先级的线程,可以被⼀个运⾏在PASSIVE_LEVEL优先级⾼的线程给抢占。所有微软说:
The thread scheduler considers only thread priority, and not IRQL, when preempting a thread. If a thread running at
IRQL=APC_LEVEL blocks, the scheduler might lect a new thread for the processor that was previously running at PASSIVE_LEVEL.
线程相关的IRQL,可以将线程想象为⼀个伪CPU,此CPU只有三个LEVEL:PASSIVE_LEVEL,Intermediate level and APC_LEVEL.
IRQL PASSIVE_LEVEL in a critical region
Code that is running at PASSIVE_LEVEL in a critical region is effectively running at an intermediate level between
PASSIVE_LEVEL and APC_LEVEL. Calls to KeGetCurrentIrql return PASSIVE_LEVEL. Driver code can determine whether it is operating in a critical region by calling the function KeAreApcsDisabled (available in Windows XP and later releas).
Driver code that is running above PASSIVE_LEVEL (either at PASSIVE_LEVEL in a critical region or at APC_LEVEL or higher) cannot be suspended. Almost every operation that a driver can perform at
PASSIVE_LEVEL can also be performed in a critical region. Two notable exceptions are raising hard errors and opening a file on storage media.
IRQL APC_LEVEL
APC_LEVEL is a thread-specific IRQL that is most commonly associated with paging I/O. Applications cannot suspend code that is running at IRQL=APC_LEVEL. The system implements fast mutexes (a type of synchronization mechanism) at
APC_LEVEL. TheKeAcquireFastMutex routine rais the IRQL to APC_LEVEL, and KeReleaFastMutex returns the IRQL to its original value.
The only difference between a thread that is running at PASSIVE_LEVEL with APCs disabled and a thread that is running at APC_LEVEL is that while running at APC_LEVEL, the thread cannot be interrupted to deliver a special kernel-mode APC.
Thread 进⼊APC_LEVEL⽅式:
1. Call KeAcquireFastMutex
2. Delivery a APC
3. KeRaiIrql (⼀般不⽤)等。
使⽤Fast Mutex进⼊APC_LEVEL后,对于其它线程,若要获取此Mutex,则会被设置为等待状态。对于线程⾃⼰⽽⾔,微软说:
Code paths that are protected by a fast mutex run at IRQL=APC_LEVEL, thus disabling delivery of all APCs and preventing the thread from suspension.
即:阻⽌响应任何APC,⽽且线程不能被挂起(suspend),为什么不能被挂起?因为操作系统实现线程挂起的⽅式,就是Delivery APC,在APC的回调函数⾥⾯等待⼀个信号量(这个是我查阅WRK中找到的答案)。由于运⾏在APC_LEVEL上,会disabling delivery of all APCs。
如果将有⼀个线程理解为⼀个伪CPU,此CPU只有三个LEVEL:PASSIVE_LEVEL,Intermediate level and APC_LEVEL. 然后将Delivery APC当做⼀个中断来处理,使⽤微软的中断规则来处理:When a processor is running at a given IRQL, interrupts at that IRQL and lower are masked off (blocked) on the processor. 就可以理解为CPU在APC_LEVEL上,屏蔽了所有等于和⼩于它的中断。
APC有三种:kernel normal apc, special kernel normal apc, and ur mode apc。Delivery a APC,此APC并不是会马上运⾏,要看情况⽽定,这个情况很复杂,不在本⽂说明,可以去微软MSDN寻找答案。
另外⼀个问题:

本文发布于:2023-05-12 13:17:17,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/888091.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:级别   中断   线程   调度
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图