|
Linux下面的中断分两种: 同步的中断,也称为异常,之所以称为"同步",是因为这些异常是在程序执行的时候某条语句触发的,比如除0错误,缺页异常等等,有名的段错误也属于其中的一种,这个时候,你的程序不能继续往下走,而必须对这些异常做出回应,也就是处理. 异步的中断,也就是中断,之所以称为"异步",是因为这些中断是在当前指令之外的指令触发的.比如你的程序正在执行,来了一个I/O请求,或者定时器到时间被触发了,等等.也就是说,程序无法预知中断在什么时候到来.
有点儿乱了,小结一下:中断分为两种,同步的中断叫做异常,一般由程序中的错误触发;异步的中断叫做中断,一般由当前程序外部触发,比如IO请求,定时器等触发.
每一个中断与一根IRQ线(Interrupt ReQuest (IRQ) line)对应,而IRQ是连接到可编程中断控制器(Programmable Interrupt Controller,简称PIC)上的.它完成下面的工作: 1) 检查与之相连的IRQ,看看哪个IRQ被触发了,选择最小的被触发的IRQ. 2) 将被中断的IRQ转换为一个中断向量 3) 将中断向量存放在IO端口,CPU可以通过数据线读取该中断向量 4) 发出INTR指令,告诉CPU:有一条中断被触发了 5) 在以上步骤之后,PIC等待CPU对这个中断做出响应,这段时间内PIC不会去检查新的中断.当CPU处理完这个中断后,PIC再去清空INTR线以接收新的中断. 6) 重复第一步
以上是PIC所做的,简单的说:监控IRQ,将被触发的IRQ转换为中断向量,然后通知CPU.
下面来看看CPU的控制单元是怎么做的.
<<深入理解Linux内核>>中对这部分说的比较详细了(4.2.4节),下面做一点辅助解释性的说明: 1) 首先,每个中断向量都与与之对应的处理程序,可以简单的理解为,这是一个大的数组,数组索引是中断向量,而存放的元素是函数指针,也就是对这些中断进行处理的函数.在系统初始化的时候初始化每个中断向量的处理函数.
2) 书中的一段话,看着有点儿令人费解的:Before dealing with that instruction, the control unit checks whether an
interrupt or an exception occurred while the control unit executed the previous
instruction. 实际上,这个查询操作对程序来说是透明的,是CPU的控制单元自己去做的事情,如果查询到了有中断被触发,再去调用上面已经注册的处理函数.至于每次执行指令之前是怎么做到高效查找的,我不清楚,哪位知道的麻烦告知一下.
3)中断向量的分类为: 从0~31的向量对应于异常和非屏蔽中断。
从32~47的向量(即由I/O设备引起的中断)分配给屏蔽中断。
剩余的从48~255的向量用来标识软中断。Linux只用了其中的一个(即128或0x80向量)用来实现系统调用。当用户态下的进程执行一条int 0x80汇编指令时,CPU就切换到内核态,并开始执行system_call( )内核函数
4) 由于中断被触发时需要保护现场,所以在发生中断调用处理函数之前需要保护现场,也就是一些寄存器指针;而中断处理完毕后需要恢复现场,因此需要将这些寄存器恢复.当然,在切换的时候,还需要考虑程序的运行权限等等.
以上就是对中断和异常处理的大体流程.
|