Linux内核学习笔记:中断与异常

tchonggang 2012-03-31

中断分为同步中断与异步中断。同步中断也叫异常是CPU执行特定的指令产生的事件,他打断CPU正常执行的指令而执行设定好的指令。异步中断也叫中断是由CPU外部中断信号产生的,每个CPU都有一个或多个中断引脚,当引脚上出现中断中断信号的时候,CPU就会停止执行当前的指令而去执行特定的代码。在linux中,中断处理至关重要,它影响着整个系统的性能。中断程序运行时,当前进程Current宏无效,所以中断程序是一个单独的内核控制路径,不能够进行进程切换。

因为中断的特殊性,所以中断处理设计就必须考虑以下几点:

(1)中断处理时间尽可能短,这个可以通过一定的方法使得中断分阶段进行。

(2)中断嵌套的允许,这样极大缩短了中断延迟

(3)关中断的尽可能时间短,次数少。

x86系统中使用中断描述符来描述各种中断,中断描述符表是个系统表,首地址存放在idtr寄存器中。中断描述符中装有段选择符以及段内偏移量,这个来确定中断处理程序的地址。

一. 内核初始化中断描述符表

中断描述符表必须在开中断时初始化,初始化这个表,linux有两个阶段。第一个阶段是初步初始化,在中断描述符表中,插入相同的表项,中断描述符表有256相,这个表项指向的中断处理程序,只是保存一些寄存器,然后打印“Unknown interrupt”,然后就退出。第二阶段,linux用有意义的中断处理程序的地址填充表项。x86体系结构中256个中断向量分配如下:

0-19        非屏蔽中断与异常

20-31       保留

32-127      外部中断

128         系统调用异常

129-238     外部中断

......

二. 中断与异常的硬件处理

在中断发生时,CPU硬件首先要完成一定的工作,使得程序计数器能够正确跳转到中断处理程序中。x86体系结构的中断硬件处理如下:

(1) 通过读取中断控制器的IO端口,或得中断号,并且由此中断号在中断描述符表中找到相应的中断描述符。

(2)检查中断的权限。总体的原则是引起中断的程序的特权级别CPL(当前特权级)必须高于低于中断处理程序的特权。

(3)检查是否发生特权级的变化,也就是检查是在内核态发生的中断,还是在用户态发生的中断。如果在用户态发生的中断,内核发生中断CPU肯定切换到了内核态,所以特权级,肯定发生了变化。如果在内核态发生的中断,特权级就没有变。如果是由用户态切换到内核态那么,在ss和esp中还保留这用户态堆栈的地址,所以得用内核态的地址填充。

(4)装载cs,eip地址,值是在中断描述符表中获取的。

三. 同步中断:异常的内核处理

CPU产生的异常,内核都当作错误处理。但是有一个异常是linux利用CPU高效管理硬件的前提,那就是缺页异常,注意,同步中断当前进程有效。异常处理程序一般分为三部分:

(1) 在内核堆栈中保存大多数CPU寄存器的内容

这部分是用汇编程序编写的,首先将C中断处理函数的地址压入堆栈,然后保存8个C语言可能用到的寄存器的值到内核栈中,把栈中esp+36处的硬件出错码拷贝到edx寄存器中,并在这个位置填-1(硬件出错吗是),然后把esp+32出的C中断处理程序地址装入edi,在这个位置写入es的值。把栈顶地址保存在eax寄存器中。然后调用在edi中高级C函数

(2) 调用高级C语言处理异常

大部分的C异常处理程序都是把硬件出错码保存在当前进程的进程描述符中。然后给进程发送一个信号。异常处理程序还检查发生异常是在用户态或者内核态,如果是在内核态,那么说明内核有BUG,调用die函数,使得系统产生oops,并杀死当前进程。

(3) 从异常返回

相关推荐