中断请求级

中断请求级
	在设计windows的时候,设计者3将中断请求划分为软件中断和硬件中断,并将这些中断都映射成不同级别的中断请求级(IRQL)。同步处理机制很大程度上依赖于中断请求级。
	
1.中断请求(IRQ)与可编程中断控制器(PIC)
	中断请求(IRQ)一般有两种,一种是外部中断,也就是硬件产生的中断,另一种由软件指令int n产生的中断。
	PIC的中断向量
	
	IRQ编号						设备名称					用途
	IQR0							Time						计算机系统计时器
	IRQ1							KeyBoard				键盘
	IRQ2							RedirectIRQ9		与IRQ9相接,MPU-401 MDI使用该IRQ
	IRQ3							COM2						串口设备
	IRQ4							COM1						串口设备
	IRQ5							LPT2						建议声卡使用该IRQ
	IRQ6							FDD							软驱传输控制用
	IRQ7							LPT1						打印机传输控制用
	IRQ8							CMOS Alert			即时时钟
	IRQ9							RedirectIRQ2		与IRQ2相接。可设定给其他硬件使用
	IRQ10							Reversed				建议保留给网卡使用该IRQ
	IRQ11							Reversed				建议保留给AGP显卡使用
	IRQ12							PS/2Mouse				接PS/2鼠标,若无也可设定给其他硬件使用
	IRQ13							FPU							协处理器用,例如FPU(浮点运算器)
	IRQ14							PrimaryIDE			主硬盘传输控制用
	IRQ15							SccondaryIde		从硬盘传输控制用
	
2.高级可编程控制器(APIC)
	传统PC一般使用2片Intel8259A中断控制器。然后在X86计算机基本都是用高级可编程控制器,即Advanced Programmable Interrupt Controller(APIC)。
	(见末尾图片处)
	
3.中断请求级(IRQP)
	在APIC中,IRQ的数量被增加到了24个,每个IRP有各自的优先级别,正在运行的线程随时可以被中断打断,进入到中断处理程序。当优先级搞的中断来临时,处在优先级低的中断处理程序,也会被打断,
进入到更高级别的中断处理函数。
	Windows将中断的概念进行了扩展,提出了一个中断请求级(IRQL)的概念。其中规定了32个中断,分别是0-2级别为软件中断,3-31级别为硬件中断(这里包括APIC中的24个中断),其中数字从0-31,
优先级别啄次递增。
	windows将24个IRQ映射到了从DISPATCH_LEVEL到PROFILE_LEVEL之间,不同硬件的中断处理程序运行在不同的IRQL级别中。硬件的IRQL称为设备中断请求级,或者简称DIRQL。Windows大部分时间运行在软件中断级别中。
当设备中断来临时,操作系统提升IRQL至DIRQL级别,并且运行中断处理函数。当中断处理函数结束后,操作系统把IRQL降到原来的级别。
	HIGH_LEVE    	31
	POWER_LEVEL 	30
	IPI_LEVEL			29
	CLOCK2_LEVEL	28
	CLOCK1_LEVEL	28
	PROFILE_LEVEL	27
	......
	DISPATCH_LEVEL 2
	APC_LEVEL			 1
	PASSIVE_LEVEL	 0		
	
	用户模式的代码运行在最低优先级的PASSIVE_LEVEL级别。驱动程序的DriverEntry函数、派遣函数、AddDevice等函数一般都运行在PASSIVE_LEVEL级别,它们在必要时可以申请进入DISPATCH_LEVEL级别。
	Windows负责线程调度的组件是运行在DISPATCH_LEVEL级别,当前的线程运行完时间片后,系统自动从PASSIVE_LEVEL级别提升到DISPATCH_LEVEL级别。当线程切换完毕后,操作系统又从DISPATCH_LEVEL级别降到PASSIVEL级别。

4.线程调度与线程优先级
	在应用程序的编程中,经常会听到线程优先级的概念。线程优先级和IRQL是两个容易混淆的概念。所有应用程序都运行在PASSIVE_LEVEL级别上,它的优先级别最低,可以被其他IRQL级别的程序打断。
线程优先级只针对应用程序而言,只有程序运行在PASSIVE_LEVEL级别才有意义。
	线程优先级是指某线程是否有更多的几号运行在CPU上,线程优先级高的线程有更多的机会被内核调度。负责调度线程的内核组建运行在DISPATCH_LEVEL级的IRQL上,这时候所有应用程序的线程都停止,等待被调度。
	ReadFile内部创建IRP_MJ_READ,然后这个IRP被传递到驱动程序的派遣函数中。这时候派遣函数运行于ReadFile所在的线程中,或者说ReadFile和派遣函数位于同一个线程上下文中。

5.IRQL的变化
	为了更好地理解IRQL概念,笔者在下面详细描述了一个线程的运行过长。这个线程在运行中,被一个中断打断,并且在中断服务执行时,被更高级别的中断打断,线程的运行分为以下几个阶段。
	阶段1:一个普通线程A正在运行。
	阶段2:这个时刻有一个中断发送,它的IRQL为0xD。CPU中断当前运行的线程A,将IRQL提升至0xD级别。
	阶段3:这个时候有一个更高优先级的中断发送,它的IRQL是0x1A。这时候CPU将IRQL提升至0x1A级别。
	阶段4:这时候又有一个中断发送,但它的IRQL为0x18,低于上一个中断优先级。CPU不会理睬这个中断。
	阶段5:这时候IRQL为0x1A的中断结束,于是进入IRQL为0x18的中断服务。
	阶段6:这时候IRQL为0x18中断结束,于是进入IRQL为0xD的中断服务。
	阶段7:最后IRQL为0xD的中断结束,操作系统恢复线程A。
	线程运行在PASSIVE_LEVEL级别,这个时候操作系统随时可能将当前线程切换到别的线程。但是如果提升IRQL到DISPATCH_LEVEL级别,这时候不会出现线程的切换。这是一种很常用的通比处理机制,但这种方法只能使用于单CPU的系统。
对于多CPU的系统,需要采用别的同步处理机制。


6.IRQL与内存分页
	在使用分页内存时,可能会导致页故障。因为分页内存随时可能从物理内存交换到磁盘文件。读取不再物理内存中的分页内存时,会引发一个页故障,从而执行这个异常的处理函数。
异常处理函数会重新将磁盘文件的内容交换到物理内存中。
	页故障允许出现在PASSIVE_LEVEL级别的程序中,但如果在DISPATCH_LEVEL或者更高级别IRQL的程序中会带来系统崩溃。
	对于等于或者高于DISPATCH_LEVEL级别的程序不能使用分页内存,必须使用非分页内存。驱动程序的StartIo例程、DPC例程、中断服务例程都运行在DISPATCH_LEVEL或者更高的IRQL。
因此,在这些例程中不能使用分页内存,否则会导致系统崩溃。

7.控制IRQL提升与降低
	有时候,驱动程序中需要提升IRQL级别。在运行一段时间后,再降回原来的IRQL级别。这样做的目的一般是基于同步处理的需要。
	首先驱动程序需要知道当前状态是什么IRQL级别,可以通过KeGetCurrentIrql内核函数获取当前IRQL级别。
	然后驱动程序使用内核函数KeRaiseIrql将IRQL提高。KeRaiseIrql需要两个参数,第一个参数是提升后的IRQL级别,第二个参数保存提升前的IRQL级别。
	最后,驱动程序在某个时刻需要将IRQL恢复到以前的IRQL级别,驱动程序可以调用KeLowerIrql内核函数。
	
	VOID RasieIRQL_Test(void)
	{
		KIRQL oldirql;
		//确保当前IRQL等于或小于DISPATCH_LEVEL
		ASSERT(KeGetCurrnetIrql()<=DISPATCH_LEVEL);
		//提升IRQL至DISPATCH_LEVEL,并将先前的IRQL保存
		KeRaiseIrql(DISPATCH_LEVEL,&oldirql);
		
		//.........
		//恢复到先前的IRQL
		KeLowerIrql(oldirql);
	
	}					
	
		


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值