中断与异常

   中断分为同步中断与异步中断。同步中断也叫异常是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) 从异常返回
四. 异步中断
        异步中断,当前进程是无效的。异步中断分为:IO中断,时钟中断,处理器之间中断。下面重点学习linux的IO中断处理。所有中断处理程序都执行四个相同的工作。
(1)在内核态保存IRQ的只和寄存器的值
(2)应答中断
(3)执行这个IRQ的所有中断服务例程。
(4)中断返回
        IRQ基本的数据结构为irq_desc_t,每一个IRQ都有一个这样的数据结构。这个数据结构包括:操作可编程中断控制器的方法,中断处理程序链表首地址,中断向量的状态,以及各种锁。操作可编程中断控制器的方法用来应答中断,而action字段是中断处理程序链表首地址,这个链表是irqaction数据结构的链表。这个数据结构包含有中断处理程序地址。下面学习中断发生时,linux内核处理的过程。
(1)当CPU通过接收到一个中断的时候,首先硬件自动处理这个中断,与异常一样。
(2)然后跳转到装载在中断描述符表中的通用中断处理程序,interrupt[n]
        这个函数,首先将n-256压入堆栈,然后跳转到common_interrupt函数中。在各函数首先保存CPU相关的寄存器,跳转到do_IRQ函数中。这个函数是中断处理的主函数。
(3)do_IRQ函数
        这个函数应答中断,然后依次执行irq_desc_t数组中相应的irqaction中的中断处理函数。然后返回。
五. 从中断和异常返回
        从中断中返回意味这要恢复被中断的程序。被中断的程序有可能是以下几种:中断处理程序,可延迟函数,普通进程(包括内核态与用户态)。如果是前两种内核控制路径,在这两种控制路径执行时内核是禁止抢占的。所以考虑的情况简单。如果中断的是普通进程或者内核线程。那么在返回的时候必须考虑以下问题:
(1)挂起的进程切换请求
(2)挂起的信号
(3)进程跟踪标志
        这些标志都在进程thread_info结构中的flags中,所以返回代码必须检查这些标志,执行不同的操作。返回代码有两个ret_from_intr和ret_from_exception,分别对应着中断与异常。这两个函数从本质上做了如下的操作:
        首先将当前进程的thread_info描述符地址装载到ebp寄存器中,判断压入栈中的cs和eflags的值,确定被中断的是内核态或者是用户态。如果是内核态执行resume_kernel,如果是用户态执行resume_userspace
(1)恢复到内核态
        首先检查是否允许内核抢占,从栈中恢复现场,恢复内核程序的执行。如果允许内核抢占,检查当前进程的调度标志,如果需要调度那么调用调度程序执行进程调度。
(2)恢复到用户态
        这个主要检查是否有重新调度标志,如果有调度。还有检查信号与单步运行标志,如果设置则执行相应的处理。如果所有标志都没设置,直接恢复原来进程的执行。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值