linux内核-中断和异常

中断通常定义为一个事件,该事件改变处理器执行的指令顺序。这个事件与cpu芯片内外部硬件电路产生的电信号相对应。

同步中断:当前指令执行时的有cpu控制单元产生的,之所以成为同步,是因为只有在一条指令结束后才会发出中断。

异步中断:由其他硬件设备依照cpu时钟信号随机产生的。

同步中断和异步中断通常成为异常和中断,异常是有程序的错误产生的,或者是又内核必须处理的异常条件产生的。第一种情况下,内核通过发送一个每个unix程序员都熟悉的信号来处理异常。第二种情况下,内核执行恢复异常需要的所有步骤,入缺页,或对内核提供的一个请求。

中断信号的作用:中断信号提供了一种特殊的方式,使处理器转而去运行正常流之外的代码,当一个信号到达时,cpu必须停止他当前正在做的事情,并且切换到一个新的活动,为了做到这一点,就要在内核态堆栈保存程序计算器的当前值即eip和cs寄存器的内容,并把与中断相关的一个地址放入程序计数器。

中断处理与进程上下文切换差异:由中断或异常处理程序执行的代码不是一个进程,确切的说是一个内核控制路径,代表中段发生时正在运行的进程执行。

中断处理是由内核执行的最敏感的任务之一,因为它必须满足下列约束:

1、当内核正打算去完成一些别的事情时,中断随时会到来。因此内核的目标就是让中断尽可能的处理完,尽量把更多的处理向后延迟,关键紧急部分,内核立即执行,其余部分,内核随后执行。

2、因为内核中断随时会到来,所以内核可能在处理一个中断时,另一个中断又发生了。应该尽可能的允许这种状态,这有利于I/O设备的效率

3、尽管内核在处理一个中断时可以接受另一个中断,但是内核代码中还是存在一些临界区,在临界区中中断必须被禁止。应当尽可能的限制这样的临界区,应该在大部分时间,内核已开中断的方式运行。

中断和异常:

中断

可屏蔽中断:I/O设备发出的所有中断请求都产生可屏蔽中断。可屏蔽中断可以处于两种状态:屏蔽的非屏蔽的;一个屏蔽的中断只要还是屏蔽的,控制单元就忽略它。

非屏蔽中断:只有几个危急事件(如硬件故障)才引起非屏蔽中断,总是有cpu辨认。

异常:

处理器探测异常:故障、陷阱、异常终止、编程异常

故障:一般可以纠正,一旦纠正,程序就可以在不是连贯性的情况下重新开始。保存eip中的值是引起故障的指令。如缺页。

陷阱:在陷阱指令执行后立即报告;内核把控制路径返回给程序后就可以继续它的执行而不失连贯性。保存在eip中的值是指令执行的下一条地址。陷阱的主要用途是为了挑食程序。

异常终止:产生一个严重的错误;控制单元出了问题,不能在eip寄存器中保存引起异常的指令所在的确切位置。异常终止用来报告严重的错误,如硬件故障或系统表中无效的值或不一致的值。

编程异常:在编程者发出请求时发生的,例如检查溢出或越界。

IRQ和中断:每个能够发出中断请求的硬件设备控制器都有一个名为IRQ的输出线,所有的IRQ都与一个名叫可编程中断控制器的硬件电路的引脚相连,可编程中断控制器执行下列动作:

1、监视IRQ线,检查产生的信号。如果有两条或两条以上的IRQ线上产生信号,就选择引脚编号较小的IRQ线。

2、如果一个音符信号出现在IRQ 线上:

a把接收到的引发信号转换成对应的向量。b 把这个向量存放在中断控制器的一个I/O端口上,从而允许CPU通过数据总线读此向量

c吧引发信号发送到处理器的intr引脚,即产生一个中断。

d等待,知道cpu通过把这个中断信号写进可编程中断控制器的一个I/O端口来确认他,这种情况下,清INTR线。

3返回第一步

传统的PIC是由两片8259A风格的外部芯片级联的方式连接在一起的。每个芯片可以处理多大8个不同的IRQ线。

高级可编程中断控制器

为了充分发挥SMP体系结构的并行性,能够把中断传递给系统中的每个CPU至关重要。基于此理由,引入了一种名为I/O高级可编程控制器的新组件-APIC,每个cpu都含有一个本地APIC,每个本地APIC都有32位寄存器、一个内部时钟、一个本地定时设备以及为本地APIC中断保留的IRQ线LINT0和LINT1。所有的本地APIC连接到一个外部I/OAPIC,形成一个多APIC系统。

来自外部硬件设备的中断请求以两种方式可以在cpu之间分发。

静态分发:IRQ信号传递给重定向表相应项中所列出的本地APIC。中断立即传递给一个特点的cpu,或一组cpu。

动态分发:如果处理器正在执行最低优先级的进程,IRQ信号就传递给这种处理器的本地APIC

如果两个或多个cpu共享最低优先级,就利用仲裁技术在这些cpu之间分配负荷。

当中断传给cpu时,其相应的仲裁优先级就自动设置为0,而其他每个cpu的仲裁优先级都增加1.当仲裁优先级寄存器的值大于15时,就把他设置为获胜的cpu的前一个仲裁优先级加1;因此中断以轮转方式在cpu之间分发。且具有相同的优先级。

中断描述符表:

任务门:当中断信号发生时,必须取代当前进程的那个进程的TSS选择符放在任务门中。

中断门:包含段选择符和中断或异常处理程序的段内偏移量。当控制权转移到一个适当的段时,处理器清IF标志,从而关闭将来会发生的可屏蔽中断。

陷阱门:与中断门类似,只是控制权传递到一个适当的段处理器时,不修改IF标志。

中断和异常的硬件处理:当执行了一条指令后,cs和eip包含下一条指令的逻辑地址。在处理那条指令前,控制单元会检查是否已经发生了一个中断或异常。如果发生,则:

1、确定与中断或异常关联的向量i;

2、读有idtr寄存器指向的IDT表的第i项

3、从gdtr寄存器获取gdt的基址,并在gdt中查找,以读取idt表项中选择符所标示的段选择符。这个描述符指定中断或异常处理程序所在段的基址

4、确信中断由授权的发生源发出的。讲当前的特权级cpl存放在cs寄存器的低两位与段描述符的描述符特权级相比较,如果cpl小于dpl,就产生异常。

5、检查是否发生了特权级的变化,也就是说cpl是否不同于段选择符的dpl,如果是,控制单元必须使用与新的特权级的相关的栈。

6、如果故障已经发生,用引起异常的指令地址装载cs和eip寄存器,从而使这条指令再次执行。

7、在栈中保存eflags、cs、诶片的内容。

8、如果异常产生了一个硬件出错吗,则将他保留在栈中

9、装载cs、eip寄存器,其值分别是IDT表中第i项门描述符的段选择符和偏移量字段。

中断处理程序执行完后,相应的的处理程序必须产生一条iret指令,把控制权转交给中断的进程。

中断或异常处理程序的嵌套执行

内核控制路径可以任意嵌套;一个中断处理程序可以被另一个中断处理程序“中断”,因此引起内核控制路径的嵌套执行,其结果是,对中断进行处理的内核控制路径,最后一部分指令讲执行上次打断的内核控制路径,此时cpu仍处于内核态。

允许内核控制路径嵌套是要付出代价的,那就是中断处理程序必须永不阻塞,就是说,中断处理程序运行期间不能发生进程切换。事实上,嵌套的内核控制路径恢复执行时,所有的数据都在内核态堆栈上。

假定内核没有bug,那么大多数异常就只在cpu处于用户态时发生。事实上,异常要么由编程错误引起,要么是调试程序,然而缺页异常发生在内核态,当处理这样一个异常时,内核可以挂起当前进程,并用另一个进程代替他,知道请求的页可以使用的为止。因为缺页异常从不进一步引起异常,所以与异常相关的嵌套至多两个内核控制路径叠在一起。

一个中断处理程序既可以抢占其他的中断处理程序,也可以抢占其他的异常处理程序。相反,异常处理程序从不抢占中断处理程序。在内核态能触发的唯一异常就是缺页异常。

基于以下这两个原因,linux交错执行内核控制路径:

1、为了提高可编程中断控制器和设备控制器的吞吐量。假定设备控制器在一条IRQ线上产生了一个信号,pic把这个信号转化为外部中断,然后pic和设备控制器保存阻塞,一直到pic从cpu处接受一个应答信息。由于内核控制路径交错执行,内核即使正在处理前一个中断,也能发送应答。

2、为了实现一种没有优先级的中断模型。因为每个中断处理程序都可以被另一个中断处理程序延缓,因此,在硬件设备之间没必要建立预定义优先级。简化了代码,提高了可移植性。

中断门、陷阱门及系统门

上面讲到intel提供的三种类型的中段描述符。linux使用与intel稍有不同的细目分类和术语,进行如下分类。

中断门:用户态的进程不能访问的一个intel中断门。所有的linux中断处理程序都通过中断门激活,并全部限制在内核态。

系统门:用户进程可以访问一个陷阱门。通过系统门来激活三个Linux异常处理程。

陷阱门:用户态的进程不能访问一个intel陷阱门。大部分Linux异常处理程序都通过陷阱门来激活。

任务门:不能被用户态进程访问的intel任务门。Linux对异常处理程序是由任务门激活的。

中断处理:内核只要给引起异常的进程发送一个Unix信号就能处理大多数异常。因此要采取行动被延迟,直到进程接收到这个信号。

三种中断类型:I/O中断 某些I/O设备需要关注;相应的中断处理程序必须查询设备以适当的操作过程。

时钟中断:某种时钟产生一个中断;这种中断告诉内核一个固定的时间间隔已经过去了。

处理器间中断:多处理器系统中一个cpu对另一个cpu中断。

中断处理程序的灵活性是以两种不同的方式实现的,讨论如下:

IRQ共享:中断处理程序执行多个中断服务例程。每个ISR是一个与单独设备相关的函数。每个ISR都被执行,以验证它的设备是否需要关注;如果是,当设备产生硬件中断时,就执行所需要执行的所有操作。

IRQ动态分配:一条IRQ线在可能的最后时刻蔡玉一个设备驱动程序关联;例如,软盘设备的IRQ线只有在用户访问软盘设备时才会分配。这样,即使几个硬件设备并不共享IRQ线,同一个IRQ向量也可以由这几个设备在不同时刻使用。

Linux把紧随的中断要执行的操作分为三类:

紧急的:这样的操作诸如:对pic应答中断,对pic或设备控制器重编程,或者修改由设备和处理器同时访问的数据结构。这些都能尽快的执行,紧急操作要在一个中断处理程序内立即执行,而且是在可屏蔽中断的情况下。

非紧急的:修该那些只有处理器才修改的数据结构。这些操作也要很快地执行,因此,它们由中断处理程序立即执行,但必须在开中断的情况下。

非紧急可延迟的:这样的操作诸如:把缓冲区的内容拷贝到某个进程的地址空间。

如果一个中断内核没有处理,那么这个中断就是意外中断,也就是说,与某个IRQ线相关的中断例程不存在,或者与某个中断线相关的所有例程都识别不出是否是自己的硬件设备发出的中断。

IRQ在多处理器系统上的分发

Linux遵循对称多处理模型;这意味着,内核从本质上对任何一个cpu都不应有偏爱。多APIC系统有复杂的机制在cpu之间动态分发IRQ信号。多APIC系统使用本地APIC仲裁优先级寄存器中的值。因为这样的值在每次中断后都会改变,因此,IRQ信号就公平地在所有CPU之间分发。

软中断及tasklet
由内核执行的几个任务之间有些不是紧急的Lz必要的情况下可以延迟一段时间。可延迟中断从中断处理程序中抽出来有助于使内核保持较短的响应时间。
软中断是利用硬件中断的概念,用软件方式进行模拟,实现宏观上的异步执行效果。很多情况下,软中断和"信号"有些类似,同时,软中断又是和硬中断相对应的,"硬中断是外部设备对CPU的中断","软中断通常是硬中断服务程序对内核的中断","信号则是由内核(或其他进程)对某个进程的中断"(《Linux内核源代码情景分析》第三章)。
软中断的一种典型应用就是所谓的"下半部"(bottom half),它的得名来自于将硬件中断处理分离成"上半部"和"下半部"两个阶段的机制:上半部在屏蔽中断的上下文中运行,用于完成关键性的处理动作;而下半部则相对来说并不是非常紧急的,通常还是比较耗时的,因此由系统自行安排运行时机,不在中断服务上下文中执行。bottom half的应用也是激励内核发展出目前的软中断机制的原因。
软中断是linux系统原“底半处理”的升级,在原有的基础上发展的新的处理方式,以适应多cpu 、多线程的软中断处理。
软中断是实现系统API函数调用的手段
函数调用时将返回地址和CPU状态寄存器内容压栈,函数执行完毕后出栈返回断点继续执行。
软中断调用时将返回地址和CPU状态寄存器内容压栈,修改特权级,根据中断号查找中断向量表,找到ISR中断服务例程地址,跳转执行。
综上,函数调用和软中断调用的区别是,软中断多了修改特权级和查找中断向量表的功能,其他部分完全一样。
一般,系统程序由软件公司实现且不开源,你无法知道系统API函数的偏移地址,而且你写的应用程序和软件公司提供的系统程序是完全分开的,编译器无法将二者链接在一起,同时,系统程序需要核心态特权才能运行,此时用函数调用的办法是无法调用系统API函数的。解决这个问题的方法是使用软中断,当应用程序需要调用API时,就先设置功能号(如AX=0H),然后触发软中断(如INT 80H)。系统程序设置好中断向量表。这样,应用程序就可以间接找到系统API了。
有了软中断,就可以实现应用程序的动态加载。就像WINDOWS/Linux那样,应用程序和系统程序分别开发,不在一起编译连接,应用程序通过软中断调用系统提供的功能。

tasklet 类似内核定时器在某些方面. 它们一直在中断时间运行, 它们一直运行在调度它们的同一个 CPU 上, 并且它们接收一个 unsigned long 参数. 不象内核定时器, 但是, 你无法请求在一个指定的时间执行函数. 通过调度一个 tasklet, 你简单地请求它在以后的一个由内核选择的时间执行. 这个行为对于中断处理特别有用, 那里硬件中断必须被尽快处理, 但是大部分的时间管理可以安全地延后到以后的时间. 实际上, 一个 tasket, 就象一个内核定时器, 在一个"软中断"的上下文中执行(以原子模式), 在使能硬件中断时执行异步任务的一个内核机制.

工作队列:在Linux2.6中引入工作队列,他们允许内核函数被激活,而且稍后有一种叫做工作者线程的特殊内核线程来执行,可延迟函数和工作队列非常相似,但是他们还是有很大区别的:用运行延迟函数运行在中断上下文中,而工作队列函数运行在进程上下文。因为,中断上下文不可能发生进程切换。可延迟函数和工作队列中的函数都不能访问进程的用户态地址空间。事实上,可延迟函数被执行时不能有任何正在执行的进程。另一方面,工作队列中的函数由内核来执行,因此根本不存在他需要访问用户态地址空间的可能性。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值