[Advanced]中断

前言:

写这篇文章纯属意外,源自前几日与一位网友在论坛谈论中断的本质。技术讨论总是好的,这种感觉也很不错,同时也觉得比较有意义,所以,想了一想,不如写下来。当然这一篇文章肯定涉及的内容不会太多,主要讲异步中断,不涉及异常等内容(虽然异常的理解与中断其实很相似)。而对于真正的有关中断的内容我准备留待写操作系统的时候再详细描述,并且结合xv6操作系统来进行代码解析如何实现中断机制。


何为中断,何为中断处理?

让我们想象一下,我们现在电脑前观看DVD影片,突然这时候,一个电话打了进来,我们很自然的操作就是暂停影片,然后根据铃声,找到电话所在处,然后去接电话,接完电话后,我们再回过头继续播放影片。是的,这个简单的例子就描述了中断与中断处理的流程。只要理解了这个例子,其实就理解了中断处理。

首先,在这个例子中,播放DVD影片就是你正常处理的事情,如果我们换做计算机的世界,那么此时的CPU就是在正常的执行预定的程序;

然后,当铃声来临时,则是在通知你电话响了,你需要去接电话,你很自然的反应当然是暂停影片,然后根据铃声找到电话所在处,去接电话,如果换做计算机的世界,则是中断控制器(如8259A)告诉CPU有地方发生了中断,需要去进行中断处理,CPU这时候则会保存好“现场”,即相关寄存器的值,然后根据特定的中断请求(IRQ)在中断向量表中找到相关中断处理程序入口地址,以期调用相关中断程序进行中断处理;

随后,你找到电话后,进行了电话通话,如果换做计算机的世界,则是CPU调用了正确的中断处理程序,进行了中断处理;

最后你处理完了电话,你回到电脑前,继续观看你暂停前的影片,如果换做计算机的世界,则是CPU恢复“现场”,即相关的寄存器的值,随后继续执行中断发生前的程序。


我们这时候也可以发现,在中断处理中,CPU并未主动“关心”过中断,而只是在中断发生后,再去处理中断——而这点这是那位网友所迷惑的。那位网友提出中断的本质为轮询(Polling)机制,然则这其实并非操作系统对中断提出的处理机制。若是轮询机制,那么在上述的例子中,你在观看影片时,你每次都会去看一下电话一眼,看是不是有电话来,这不是在浪费生命吗?其实,只需要在电话铃声响时,再去处理电话事件即可,剩下的美妙时间留给影片多好。同样的,犹如我现在敲击的键盘一样,我每敲击一次,都会产生一次键盘中断信号,那么,假如我长时间不使用键盘了,我长时间都是在使用鼠标,如果是轮询机制,CPU也要每执行一次都要来看一下键盘是否输入吗?这也是在浪费CPU的资源。


中断处理的详细流程(留给感兴趣的同学,我这里也不做过多的名词解释了)

中断处理过程1(开始):从CPU收到中断事件后,打断当前程序或任务的执行,根据某种机制跳转到中断服务例程去执行的过程。其具体流程如下:
1) CPU在执行完当前程序的每一条指令后,都会去确认在执行刚才的指令过程中中断控制器(如:8259A)是否发送中断请求过来,如果有那么CPU就会在相应的时钟脉冲到来时从总线上读取中断请求对应的中断向量;
2) CPU根据得到的中断向量(以此为索引)到IDT中找到该向量对应的中断描述符,中断描述符里保存着中断服务例程的段选择子;
3) CPU使用IDT查到的中断服务例程的段选择子从GDT中取得相应的段描述符,段描述符里保存了中断服务例程的段基址和属性信息,此时CPU就得到了中断服务例程的起始地址,并跳转到该地址;
4) CPU会根据CPL和中断服务例程的段描述符的DPL信息确认是否发生了特权级的转换。比如当前程序正运行在用户态,而中断程序是运行在内核态的,则意味着发生了特权级的转换,这时CPU会从当前程序的TSS信息(该信息在内存中的起始地址存在TR寄存器中)里取得该程序的内核栈地址,即包括内核态的ss和esp的值,并立即将系统当前使用的栈切换成新的内核栈。这个栈就是即将运行的中断服务程序要使用的栈。紧接着就将当前程序使用的用户态的ss和esp压到新的内核栈中保存起来;
5) CPU需要开始保存当前被打断的程序的现场(即一些寄存器的值),以便于将来恢复被打断的程序继续执行。这需要利用内核栈来保存相关现场信息,即依次压入当前被打断程序使用的eflags,cs,eip,errorCode(如果是有错误码的异常)信息;
6) CPU利用中断服务例程的段描述符将其第一条指令的地址加载到cs和eip寄存器中,开始执行中断服务例程。这意味着先前的程序被暂停执行,中断服务程序正式开始工作。


中断处理过程2(结束):每个中断服务例程在有中断处理工作完成后需要通过iret(或iretd)指令恢复被打断的程序的执行。CPU执行IRET指令的具体过程如下:

1) 程序执行这条iret指令时,首先会从内核栈里弹出先前保存的被打断的程序的现场信息,即eflags,cs,eip重新开始执行;
2) 如果存在特权级转换(从内核态转换到用户态),则还需要从内核栈中弹出用户态栈的ss和esp,这样也意味着栈也被切换回原先使用的用户态的栈了;
3) 如果此次处理的是带有错误码(errorCode)的异常,CPU在恢复先前程序的现场时,并不会弹出errorCode。这一步需要通过软件完成,即要求相关的中断服务例程在调用iret返回之前添加出栈代码主动弹出errorCode。


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值