中断和异常-中断处理

通过上面介绍,中断描述符表IDT已被初始化,并具有相应的内容;对于外部中断,还要建立中断请求队列和执行中断处理程序。

一、中断和异常的硬件处理

从硬件角度来看CPU如何处理中断和异常。假定已初始化内核,CPU已从实模式切换到保护模式。

当CPU执行当前指令后,寄存器CS和EIP中包含的内容是下一条将要执行指令的虚地址。对下一条指令执行前,CPU先要判断在执行当前指令的过程中是否发生中断或异常。如果发生一个中断或异常,那么CPU做如下事情。

(1)确定发生中断或异常的向量i(在0~255之间)。

(2)通过IDTR寄存器找到IDT,读取IDT表的第i项(或第i个门)。

(3)分两步进行有效性检查:首先是段级检查,将CPU的当前特权级CPL(存放在CS寄存器的最低两位)与IDT表中第i项段选择符中的DPL比较,如果DPL(3)大于CPL(0),产生一个“通用保护”异常,因为中断处理程序的特权级大于等于产生中断的进程的特权级。这种情况发生的可能性不大,因为中断处理程序一般运行在内核态,特权级为0。再次是门级检查,把CPL与IDT中第i个门的DPL比较,如果CPL(0)小于DPL(3),那么CPU不能穿过这个门,则产生一个“通用保护”异常,这是为了避免用户应用程序访问特殊的中断门或陷阱门。

备注:门级检查针对一般的用户程序,不包括外部I/O产生的中断或CPU内部产生的异常,如果产生中断或异常,就免去门级检查。

(4)检查特权级是否发生改变。当中断发生在用户态(特权级为3),而中断处理程序运行在内核态(特权级为0),特权级发生变化,引起堆栈切换,从用户态堆栈切换到内核态堆栈。当中断发生在内核态时,即CPU运行在内核中时,则不会切换堆栈,如图5.4所示。

总结如下:

从图5.4看出,当从用户态堆栈切换到内核态堆栈时,先把用户态堆栈的值压入中断处理程序的内核态堆栈中,同时把EFLAGS寄存器自动压入堆栈,然后把中断进程的返回地址压入堆栈。如果异常产生一个硬错误码,则将这个硬错误码也保存在堆栈中。如果特权级没有发生变化,压入堆栈的内容如图5.4(b)所示。此时,CS:EIP的值是IDT表中第i项门描述符的段选择符和偏移量的值,CPU跳转到中断或异常处理程序。

二、中断请求队列的建立

由于硬件限制,很多外部设备必须共享中断线,例如,一些PC(个人电脑)配置可以把同一条中断线分配给网卡和图形卡。由此看来,让每个中断源都必须占用一条中断线不现实。所以,仅仅用中段描述符表IDT并不能提供中断产生的所有信息,内核必须对中断线给出进一步的描述。在Linux中,为每个中断请求IRQ设置一个队列,即中断请求队列。

1、中断服务程序与中断处理程序

这里提到的中断服务程序与中断处理程序概念不同。在Linux中15条中断线对应15个中断处理程序,其名字依次为IRQ0x00_interrupt(),IRQ0x01_interrupt(),......,IRQ0x0f_interrupt()。具体来说,中断处理程序相当于某个中断向量的总处理程序,例如IRQ0x05_interrupt()是中断号为5的总处理程序,如果5号中断由网卡和图形卡共享,则网卡和图形卡分别有其对应的中断服务程序。

2、中断共享的数据结构

为让多个设备能共享一条中断线,内核定义一个irqaction的数据结构:

typedef irqreturn_t (*irq_handler_t)(int, void *); // 定义函数指针类型

struct irqaction {
         irq_handler_t handler;      //用户注册的中断服务程序,中断发生时会执行这个中断服务程序
         unsigned long flags;  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值