Linux中断一:初看Linux中断

 

中断是Linux内核中比较难而且比较重要的一部分,如果想掌握这些东西,理解是首当其冲的一个重要环节。所谓的难点,新知识,如果完全理解了原理,至少相当于掌握了80%,这对于任何知识都一样,所谓真正理解,就是要完全了解这块东西,引入的缘由以及如何引入的,特别是和其他模块之间的联系,以及包含在其中的众多思想。

 

Linux内核,说到底还是上层软件和底层硬件的桥梁。对上层,提供系统调用(当然其就是一个中断,即128或0x80向量),对硬件,提供中断机制,便是其中重要的一部分,当然还有其他方面,暂不谈。

 

0. 中断概述:
什 么是中断,简单地说就是CPU在忙着作自己的事情,这时候硬件(比如说键盘按了一下)触发了一个电信号,这个信号通过中断线到达中断控制器 8259A,8259A接受到这个信号,向CPU发送INT信号申请CPU来执行刚才的硬件操作,并且将中断类型号也发给CPU,此时CPU就丢下自己正 在做的事情,但不是随便丢到旁边而是保存了当前正在做的事情的相关资料,然后去处理这个申请,根据中断类型号找到它的中断向量(也就是中断程序在内存中的 地址),然后去执行这段程序(这段程序是已经写好的,在内存中),执行完后再向8259A发送一个INTA信号表示我已经处理完你刚才的申请。这个时候 CPU就可以继续做它刚才被打断做的事情了,这个时候刚才保存的相关信息就帮助CPU接着执行下面的程序,而不至于忘记自己刚才正在做什么。
上面说了一大堆关键词有四个:
中断源:这里的中断源是指打断CPU的事件,没有中断源中断无从谈起,它可以是硬件的也可以是软件的。
CPU:不用说中断就是要来用CPU来处理一些事情的
中断控制器8259A:硬件中断源与CPU之间的桥梁,没有它中断就无法被CPU所知道。
中断服务程序:你打断了CPU,CPU就得根据这个程序来为你办事

 

1. 再说8259A

 

在我们常见x86平台下,8259A是专门为了对8085A和8086/8088进行中断控制而设计的芯片,它是可以用程序控制的中断控制器。想当年学习8086时,老师也讲过8259A,那个时候就是懵懵的学习,机械的记忆,为什么学习这个玩意也不懂。再回过头来,单个的8259A能管理8级向量优先级中断。在不增加其他电路的情况下,最多可以级联成64级的向量优级中断系统。8259A有多种工作方式,能用于各种系统。各种工作方式的设定是在初始化时通过软件进行的。 在总线控制器的控制下,8259A芯片可以处于编程状态和操作状态,编程状态是CPU使用IN或OUT指令对8259A芯片进行初始化编程的状态。

如下图即为8259A的芯片图:

8259A其主要功能就是在有多个中断源的系统中,接受外部的中断请求,并进行判断,选中当前优先级最高的中断请求,再将此请求送到cpu的INTR端;当cpu响应中断并进入中断子程序的处理过程后,中断控制器仍负责对外部中断请求的管理。

2.  8259A及其与CPU通信工作原理

 

一个外部中断请求信号通过中断请求线IRQ,传输到IMR(中断屏蔽寄存器),IMR根据所设定的中断屏蔽字(OCW1),决定是将其丢弃还是接受。如果 可以接受,则8259A将IRR(中断请求暂存寄存器)中代表此IRQ的位置位,以表示此IRQ有中断请求信号,并同时向CPU的INTR(中断请求)管 脚发送一个信号。但CPU这时可能正在执行一条指令,因此CPU不会立即响应。而当这CPU正忙着执行某条指令时,还有可能有其余的IRQ线送来中断请 求,这些请求都会接受IMR的挑选。如果没有被屏蔽,那么这些请求也会被放到IRR中,也即IRR中代表它们的IRQ的相应位会被置1。

图中是由两片8259A级联组成的,可以响应15个中断源。由图可以看出硬件接在8259A的中断请求线上。

【插图8259A中断控制器】

当CPU执行完一条指令时后,会检查一下INTR管脚是否有信号。如果发现有信号,就会转到中 断服务,此时,CPU会立即向8259A芯片的INTA(中断应答)管脚发送一个信号。当芯片收到此信号后,判优部件开始工作,它在IRR中,挑选优先级 最高的中断,将中断请求送到ISR(中断服务寄存器),也即将ISR中代表此IRQ的位置位,并将IRR中相应位置零,表明此中断正在接受CPU的处理。 同时,将它的编号写入中断向量寄存器IVR的低三位(IVR正是由ICW2所指定的,不知你是否还记得ICW2的最低三位在指定时都是0,而在这里,它们被利用了!)这时,CPU还会送来第二个INTA信号,当收到此信号后,芯片将IVR中的内容,也就是此中断的中断号送上通向CPU的数据线。

这个内容看起来仿佛十分复杂,但如果我们用一个很简单的比喻来解释就好理解了。CPU就相当于 一个公司的老总,而8259A芯片就相当于这个老总的秘书。现在有很多人想见老总,但老总正在打电话,于是交由秘书先行接待。每个想见老总的人都需要把自 己的名片交给秘书,秘书首先看看名片,有没有老总明确表示不愿见到的人,如果没有就把它放到一个盒子里面。这时老总的电话还没打完,但不停的有人递上名片 求见老总,秘书就把符合要求的名片全放在盒子里了。老总打完电话了,探出头来问秘书:有人想见我吗?这时,秘书就从盒子里挑选一个级别最高的,并把他的名 片交给老总。

这里需要理解的是中断屏蔽与优先级判定并不是一回事,如果被屏蔽了,那么参加判定的机会也都没了。在默认情况下,IRQ0的优先级最高,IRQ7最低。当然我们可以更改这个设定,这样在下面有详细描述。

当芯片把中断号送上通往CPU的数据线后,就会检测ICW4中的EOI是否被置位。如果EOI 被置位表示需要自动清除中断请求信号,则芯片会自动将ISR中的相应位清零。如果EOI没有被置位,则需要中断处理程序向芯片发送EOI消息,芯片收到 EOI消息后才会将ISR中的相应位清零。

这里的机关存在于这样一个地方。优先权判定是存在于8259A芯片中的,假如CPU正在处理 IRQ1线来的中断,这时ISR中IRQ1所对应的位是置1的。这时来了一个IRQ2的中断请求,8259A会将其同ISR中的位进行比较,发现比它高的 IRQ1所对应的位被置位,于是8259A会很遗憾的告诉IRQ2:你先在IRR中等等。而如果这时来的是IRQ0,芯片会马上让其进入ISR,即将 ISR中的IRQ0所对应的位置位,并向CPU发送中断请求。这时由于IRQ1还在被CPU处理,所以ISR中IRQ1的位也还是被置位的,但由于 IRQ0的优先级高,所以IRQ0的位也会被置位,并向CPU发送新的中断请求。此时ISR中IRQ0与IRQ1的位都是被置位的,这种情况在多重中断时 常常发生,非常正常。

如果EOI被设为自动的,那么ISR中的位总是被清零的(在EOI被置位的情况下,8259A 只要向CPU发送了中断号就会将ISR中的相应位清零),也就是如果有中断来,芯片就会马上再向CPU发出中断请求,即使CPU正在处理IRQ0的中 断,CPU并不知道谁的优先级高,它只会简单的响应8259A送来的中断,因此,这种情况下低优先级的中断就可能会中断高优先级的中断服务程序。所以在PC中,我们总是将EOI位清零,而在中断服务程序结束的时候才发送EOI消息。

下面再来理解Linux中断的东西,效果会好一些。

3. 中断的分类
早期以及一般情况下,我们所说的中断即指由外设所产生的中断。随着计算机的迅速发展,中断不再仅仅局限于外部设备,CPU本身也会产生中断,不过我们将这种中断称为异常。

对于x86体系结构而言,中断可以分为两大类:同步中断和异步中断。同步中断即我们上面所说的异常,它是由 CPU 在执行非法命令时所产生的。之所以称为同步,是因为这种中断请求信号与代码指令同步执行,也就是说只有在一条指令执行完毕后 CPU 才会发出中断,而不是发生在代码指令执行期间。而异步中断即由外部设备产生的中断,这种中断可以随时发生,习惯上,我们将异步中断仍然称为中断。

中断可分为可屏蔽中断(Maskable interrupt)和不可屏蔽中断(Nomaskable interrupt)。异常可分为故障(fault)、陷阱(trap)、终止(abort)三类。

可屏蔽中断主要是针对外部设备所产生的中断信号,不可屏蔽中断一般是指计算机内部硬件产生的中断。由于异常是CPU发出的中断信号,与中断控制器(下文有解释)无关,因此异常不能被屏蔽。那么,异常和不可屏蔽中断有些相似点:它们均与外部设备无关,并且均不能被屏蔽。

 

上面概述中提到的中断只是中断家族中的一种叫硬件中断,总的来说可以将中断分为内部中断和外部中断,内部中断也叫异常,是由CPU产生的,当处理器执行时遇 到了由于程序员编程而导致的错误指令时,如除数为0,这些就会产生内部中断,而外部中断(硬件中断)一般都是硬件所引起的中断比如说键盘等。

这里总结一下分类,免的搞混了。

第一种分类方法:

硬件中断:也叫异步中断。

软件中断:也称作异常,同步中断

第二种分类方法:

       可屏蔽中断:外部设备所产生的中断信号

       不可屏蔽中断:计算机内部硬件产生的中断

4. 中断号
这 里所说的中断号是指外部中断即硬件中断的编号,系统为每个“中断请求线”分配了一个号,x86采用了两个8259A,一共有15个中断号,但是随着外设的 增加,这些肯定不能满足需求,所以就有了多个外设共享一个中断号。中断号是用来表明是那个设备产生了中断,比如作为时钟中断的IRQ0。这样CPU就可以 知道是那个设备产生了中断从而去处理它。
5. 中断向量
Inter x86共支持256个向量中断,为了很容易的识别每种中断源将它们从0到255进行编号,Inter将这个整数叫做中断向量,Linux对这256个中断向量的分配如下:
0~31为异常和非屏蔽中断
32~47为可屏蔽中断(硬件中断)
48~255用来表示软中断,Linux只用了其中的一个(即128或0x80向量)作为系统调用。
前面所将的中断号与中断向量之间的关系是:中断号+32 = 中断向量。中断向量的作用将在下面介绍。
中断描述符表(IDT):一个表,也叫中断向量表,每个表项叫做门描述符(gate descriptor)占8个字节,简单的说是用来存放中断处理程序入口函数地址,当然还包括了一些其他信息。其作用就是当一个中断发生时我们根据它的中 断号确定其中断向量,然后在此表中找到它的入口函数从而执行它。这个表存放在内存中的一片区域中,那么我们如何找到这个表呢?这就需要一个系统寄存器中断 描述符寄存器IDTR,在系统初始化时有一条汇编指令LIDT便可将中断描述符表的地址装进IDTR中,IDTR48位,在低字(低16位)中装的是界 限,在高双字(高32位)中装的是基址。

6. 中断服务例程

在响应一个具体的中断时,内核会执行一个函数,该函数被称为中断服务例程(Interrupt Service Routine,ISR)。每一个设备的驱动程序中都会定义相关的中断服务例程。从下面的代码可以看到,中断服务例程有两个参数,分别为int型和 void指针型。并且返回值为irqreturn_t。

//linux/include/linux/interrupt.h
typedef irqreturn(*irq_handler_t)(int,void*)	 

	//linux/include/linux/irqreturn.h
	enum irqreturn 
{
	IRQ_NONE,
	         IRQ_HANDLED,
	         IRQ_WAKE_THREAD,
	    };
	 
	 typedef enum irqreturn irqreturn_t;


 

由于irqreturn_t是一个枚举类型,因此本质上为整形。并且IRQ_NONE,IRQ_HANDLED,IRQ_WAKE_THREAD的 值一次为0,1,2。IRQ_NONE表示不处理所收到的中断请求;IRQ_HANDLED表示接收到了有效的中断请求,并且作出了正确的处理(这一点在 后文中有详细讨论)。

需要注意的是,当一个中断服务例程正在执行的时候,该中断所在所有处理器上的都会被屏蔽,以免继续接受同一条中断线上的另一个新的中断。

以上就是关于中断的基本概念,了解了它们就容易进行后续的中断分析了。

 

 

【参考】

1. 百度文档

2. 8086/88汇编语言

3. 陈莉君博客

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值