中断

1.1 为什么会有中断?

操作系统内核需要对连接到计算机上的所有硬件设备进行管理,毫无疑问这是它的份内事。如果要管理这些设备,首先得和它们互相通信才行,一般有两种方案可实现这种功能:

 1.轮询(polling) 让内核定期对设备的状态进行查询,然后做出相应的处理;

 2.中断(interrupt)让硬件在需要的时候向内核发出信号(变内核主动为硬件主动)。

第一种方案会让内核做不少的无用功,因为轮询总会周期性的重复执行,大量地耗用 CPU 时间,因此效率及其低下,所以一般都是采用第二种方案。

“如果没有中段,操作系统几乎什么都做不了,操作系统是由中断驱动的”。这句话不知道是哪个大神说的。但是这句话却说的事实,因为操作系统本身就是个死循环,这个死

循环本身做不了什么事,仅仅是保证操作系统能够周而复始的运行下去,而运行的目的是为了等候某些事情的发生。所以操作系统是被动的工作,它是被某个事件驱动所工作

的,而这个事件是以中断的形式通操作系统的。所以说操作系统是由中断驱动的。并且CPU的外设是独立于CPU的,它与CPU是同步运行的,所以,CPU抽出一点时间来处理

中段,外部设备就可以同CPU并行的工作了,整个计算机的系统就可以大幅度的提升。

中断存在的另一个重要的原因是,在保护模式下用户要访问硬件的相关资源时,需要向操作系统提出申请,由操作系统去做,之后将结果返回给用户。这样做就是为了提高安全

性。所以就有了基于中断的功能调用也就是我们常说的系统调用。

系统调用一般有两中方式:

(1)将系统调用指令封装为c的库函数,同过库函数进行系统调用。

(2)不依赖任何库函数,直接通过汇编指令INT与操作系统通信。

INT指令是在x86指令系统当中提供的一条中断指令。用来主动的产生中断信号的,去调用已经封装好的程序而获取所需的功能和所需的资源。所以说无论是BIOS中断,还是

DOS中断(都是我们常说的软中断),或者是其它类似的中断方式, 其本质并不是计算机运行当中发生了异常的情况, 而是利用了现有的中断这种机制,来实现一些系统函

数, 代码的调用,以便向高层的软件屏蔽底层硬件的细节, 从而提高编程的便利性,正确性,和可抑制性。 


1.2 什么是中断?

硬件描述:

中断是一种电信号,由硬件设备产生,并直接送入中断控制器(也就是后面说的PIC 如 8259A)的输入引脚上(中断控制器是一个简单的电子芯片),然后再由中断控制器向处理器发送相应的信号。处理器一经检测到该信号,便中断自己当前正在处理的工作,转而去处理中断。此后,处理器会通知操作系统已经产生中断。这样,操作系统就可以对这个中断进行适当的处理。

不同的设备对应的中断不同,而每个中断都通过一个唯一的数字标识,这些值通常被称为中断请求线(IRQ)。

中断(interrupt)通常被定义为一个事件,该事件改变处理器执行的指令顺序(书中描述)。

1.3什么是IRQ?

IRQ:能发出中断请求的硬件设备都有一条名为IRQ的输出线,所有的IRQ线都与可编程中断控制器(PIC)的硬件电路的输入引脚相连。

IRQ线是从0开始顺序编号的,因此,第一条IRQ线通常表示成IRQ0。与IRQn关联的Intel的缺省量是n+32,并且通过向中断控制器端口发布合适的指令,就可以修改IRQ和向量之间的映射。

可以通过对PIC编程禁止或激活IRQ线,当激活之后,原先禁止的中断不会消失,这样可以统一的处理同一类型的IRQ。

1.4 什么是 PIC?

PIC在我的理解中就是可编程的中断代理器是一个电子芯片是在硬件上原生支持的,为了帮助CPU减轻处理中断的压力。

可编程中断控制器(PIC)执行过程:
1、监视 IRQ 线,如果两条或者以上的 IRQ 线产生信号,选择引脚编号较小

2、如果只有一个引发信号

a、将它转化为对应的向量;

b、将向量存放到中断控制器的 IO 端口,允许 CPU 通过数据总线读取;

c、把引发信号发送到处理器的 INTR 引脚,即产生中断

d、等待,直到 CPU 通过吧这个中断信号写入可编程中断控制器的一个 I\O 端口来确认它,清除 INTR 线;

3、返回第一步。
如果系统只有一个单独的 CPU, 那么主 PIC 的输出线以直截了当的方式连接到 CPU 的 INTR 引脚。传统的 PIC 是由两片 8259A 风格的外部芯片以“级联”的方式连接在一起

的。每个芯片可以处理多达 8 个不同的 IRQ 输入线。因为从 PIC 的 INT 输出线连接到主 PIC 的 IRQ2 引脚,因此,可用 IRQ 线的个数限制为 15.


如果系统中包含两个或多个CPU呢?

目前针对SMP体系结构引入了高级可编程中断控制器(APIC),能够处理多个CPU的系统;多APIC系统图示:


本地APIC:32位的寄存器,一个内部时钟,一个而本地定时设备以及为本地APIC中断保留的两条额外的IRQ线LINT0和LINT1。所有本地APIC都连接到一个外部I/OAPIC,形成一个多APIC 的系统。

I/OAPIC:一组24条IRQ线、一张24项的中断重定向表、可编程寄存器,以及通过APIC总线发送和接收APIC信息的一个信息单元。中断优先级是由中断重定向表决定的,并且

是可编程的;两种中断请求的分发方式:

1)  静态分发:通过重定表将中断传递给一个特定的CPU,或一组CPU,或所有CPU。

2)  动态分发:在CPU之间根据优先级、负载情况或者CPU主动请求进行灵活调配;

处理器间中断:除了在处理器之间分发中断外,多APIC系统还允许CPU产生处理器间中断。当一个CPU希望把中断发给另一个CPU时,它就在自己本地APIC的中断指令寄存

器中存放这个中断向量和目标本地APIC的标识符。然后,通过APIC总线向目标本地APIC发送一条消息,从而向自己的CPU发出一个相应的中断。

处理器间中断是SMP体系结构到关重要的组成部分,并由Linux有效地用来在CPU之间交换信息。

1.5 中断(总称)的种类

中断通常分为同步(synchronous)中断和异步(asynchronous)中断:

(1)同步中断是当指令执行时由CPU控制单元产生的,只有在一条指令终止执行后CPU才会发出中断,同步中断也叫作异常;

(2)异步中断是由其他硬件设备依照CPU时钟信号随机产生的,异步中断叫做中断;

同步和异步的概念理解:

同步:(只有在一条指令执行完毕后CPU才会发出中断,而不是发生在代码指令执行期间)由软件产生的中断一般是由专设的指令(如X86中的“int n”,int n 汇编指令,n为

终端类型码,功能是引发中断过程)在程序中有意产生的,是主动的,同步的。只要CPU执行一条int 指令,在开始执行下一条指令之前一定会进入中断服务程序。这种主动的

中断称为“陷阱”(trap)

异步:CPU外部产生的外部中断,可以再指令之间发生,即是通常所讲的“中断”(interrupt)。

对于执行程序来说,这种“中断”的发生完全是异步的,因为不知道什么时候会发生。CPU对其的响应也完全是被动的,可以通过“关中断”指令关闭对其的响应。

中断是由间隔定时器和I/O设备产生的;异常是由程序的错误产生的,或者是由内核必须处理的异常条件产生的。

1.6中断和异常的分类

由于对于中断的分类有好多种,有些分类很细有些只是大致上的分类。有时候同一个名字在不同分类里的定义又不一样,所以让人对中断的理解有很多误区。首先我先说说自己

对于中断的分类,虽然没有书中的那么细致,但大致是没错的。

中断就是发生了某中实践需要通知CPU。所以中断按事件的来源分类,把来自CPU外部的中断就称为外部中断,而大家已经知道CPU对于外部的中断信号的接受是通过两个引

脚上连接的INTR和NMI信号线接收的,所以又可以把外部中断是否严重来划分为可屏蔽与不可屏蔽中断。 INTR上接收的信号分为可屏蔽中断(一般是一些外设的中断信号),

把NMI上的分为不可屏蔽中断(一般是电源掉电、内存读写错误)。把来自CPU内部的中断称为内中断,并且可以把内中断按主动与被动划分为软中断和异常。


下面是书中对于中断与异常的分类:


中断:
可屏蔽中断(maskable interrupt):一个屏蔽的中断只要还是屏蔽的,控制单元就忽略它。

非屏蔽中断(nonmaskable interrupt):非屏蔽中断总是由 CPU 辨认。

异常:
处理器探测异常(processor-detected exception):当 CPU 执行指令时探测到一个反常条件所产生的异常,可分为三组:

1)故障(fault):通常可以纠正,一旦纠正,程序就可以不失连贯的情况下重新开始。

2)陷阱(trap):主要用于调试程序。在陷阱指令执行后立即报告,内核把控制权返回给程序后就可以继续它的执行而不失连贯性。(调试中的断点)

3)异常中止(abort):发生一个严重错误,控制单元出了问题,不能在 eip 寄存器中保存引起异常的指令所在的确切位置。异常中止用于报告严重的错误,如硬件故障等。由

控制单元发送的这个中断信号是紧急信号,用来把控制权切换到相应的异常中止处理程序,这个异常中止处理程序除了强制受影响的进程终止外,没有别的选择。

4)编程异常(programmed exception 归为陷阱):在编程者发出请求时发生。控制单元把编程异常作为陷阱来处理,编程异常通常也叫做软中断


1.7中断信号的作用

中断信号提供了一种特殊的方式,使处理器转而去执行正常控制流之外的代码。当一个中断信号达到时,CPU必须停止它当前正在做的事情,并且切换到一个新的活动。为了做到这一点,就要在内核态堆栈保存程序计数器的当前值(即eip和cs寄存器),并把与中断类型相关的一个地址放进程序计数器。中断处理是由内核执行的最敏感的任务之一,因为它必须满足以下约束:

中断:中断到来时,内核的目标就是让中断尽可能快的处理完,尽其所能把更多的处理向后推迟。内核响应中断后需要进行的操作可以分为两部分:关键而紧急的部分,内核立即执行(top half); 其余推迟的部分,内核随后执行(bottom half)。

中断中的中断:内核可能正在处理其中一个中断时,另一个中断又发生了。因此,中断处理程序必须编写成使相应的内核控制路径能以嵌套的方式执行。当最后一个内核控制路径终止时,内核必须能恢复被中断进程的执行,或者,如果中断信号已导致了重新调度,内核能切换到另外的进程。

需被禁止的中断:尽管内核在处理前一个中断时可以接受一个新的中断,但在内核代码中还是存在一些临界区(需要保护关键变量不被修改),在临界区中,中断必须被禁止。必须尽可能地限制这样的临界区,因为,根据以前的要求,内核,尤其是中断处理程序,应该在大部分时间内以开中断的方式运行。

中断处理程序是什么?中断处理与进程切换是不是同一回事?

由中断或异常处理程序所执行的代码不是一个进程,更确切的说,它是一个内核控制路径,代表中断发生时正在运行的进程执行。作为一个内核控制路径,中断处理程序比一个进程要轻(中断的上下文很少,建立和终止中断处理所需要的时间很少)。

其实每个处理器在任何指定时间点上的活动必然概括为下列三者之一 :

1,运行于用户空间,执行用户进程;

2,运行于内核空间,执行进程上下文,代表某个特定的进程执行;

3,运行于内核空间,执行中断上下文,与任何进程无关,处理某个特定中断。

另外每一个进程都会有代表进程的task_struct结构记录着进程的状态。内核中的“调度器”通过task_struct对进程进行调度。但是,中断上下文却不是一个进程,它并

不存在task_struct,所以它是不可调度的。既然有中断上下文,为什么不存在对应的task_struct结构呢?中断的产生是很频繁的(至少每毫秒(看配

置,可能10毫秒或其他值)会产生一个时钟中断),并且中断处理过程会很快。如果为中断上下文维护一个对应的task_struct结构,那么这个结构频

繁地分配、回收、并且影响调度器的管理,这样会对整个系统的吞吐量有所影响。但是在某些追求实时性的嵌入式linux中,中断也可能被赋予

task_struct结构。这是为了避免大量中断不断的嵌套,导致一段时间内CPU总是运行在中断上下文,使得某些优先级非常高的进程得不到运行。这种

做法能够提高系统的实时性,但是代价中吞吐量的降低。所以中断处理和进程切换不是一回事,甚至中断处理程序并不是一个进程在执行,故而也没

有进程所谓的状态(运行,睡眠等);

1.7 什么是内核控制路径?

内核控制路径是指被内核执行的用于处理系统调用异常中断的指令序列;其实就是内核里面位于0xc0000000以上的函数代码,包括中断处理函数,异常处理函数、内核线程函

数;中断处理函数:硬件通知CPU,CPU调到对应地址执行;常处理函数:比如应用层执行的系统调用,触发CPU执行函数;内核线程:和其他用户线程一样,参与CPU的优

先级调度。

如何进入内核控制路径?

内核在允许中断信号到来之前,必须先准备好对它们的处理,也就是适当地初始化中断描述符表(Interrupt Descriptor Table, IDT)。中断信号一来,CPU控制单元就自动把当

前的程序计数器(eip、cs)和eflags保存到内核stack,然后把事先与发生的中断信号类型关联好的处理程序的地址(保存在IDT中)放进程序计数器。这时,就进入内核控制路

径(kernelcontrol path)中执行相应的代码。

内核控制路径是不是一个进程?(同中断处理程序)

不是,虽然也需要切换上下文,需要保存那些它可能使用的寄存器的并在返回时恢复,但这是一个非常轻的上下文切换(中断上下文)。它诞生的时候并没有发生进程切换,处

理中断的主语仍然是中断发生时正在执行的那个进程,它仍然在使用分配给它的那段时间片。

中断和异常发生时,进程的切换过程?

如果一个进程还在处理一个异常的时候,分配给它的时间片到期了,会发生什么事情呢?这取决于有没有启用内核抢占(KernelPreemption),如果没有启用,进程就继续

处理异常,如果启用了,进程可能会立即被抢占,异常的处理也就暂停了,断点会保存到该进程的内核栈中,直到schedule()再度选择此进程(注意:内核处理中断的时候,必

然会禁用内核抢占,所以这里说的是异常)。

内核控制路径的交叉执行

Linux允许内核代码路径的交错执行,即在当前内核控制路径尚未执行完的时候,允许另外一条控制路径来中断(也可以称为抢占)它。但这种交错执行不是任意的,需要满足

如下严格的规则:

(1)内核进程代码路径不能够中断任何其它内核控制路径,包括别的内核进程代码路径(这保证了Linux进程在内核中是非抢占的----当然如果是抢占内核则可以中断)。

(2)    异常处理代码可以中断内核进程代码路径,但不能够抢占中断处理路径的执行。实际上后一个特点是对中断处理程序的限制,由于异常处理总是由于当前正在运行的

代码所引起的,只有中断处理程序中不允许执行可能引起"缺页操作"的代码,才能够保证不激活异常处理程序。

(3)    中断处理程序可以中断任何一个内核进程代码路径,也可以中断异常处理路径,以及与其它的中断处理程序交错执行。

1.8 什么是中断描述符表?

中断描述符表是一个系统表,它与每一个中断或异常向量相联系,每一个向量在表中有相应的中断或异常处理程序的入口地址。内核在允许中断发生前,必须适当地初始化

IDT。DT的格式:IDT表中的每一项对应一个中断或异常向量,每个向量由8个字节组成。因此,最多需要256*8=2048字节来存放IDT。硬件提供的IDT有三种类型:


以上显示了三种描述符表中的64位的含义,其中40-43位的type字段表示描述符的类型;

三种描述符如下:

任务门:

当中断信号发生时,必须取代当前进程的哪个进程的TSS选择符存放在任务门中。

中断门:

包含段选择符和中断或异常处理程序的段内偏移量。

陷阱门:

与中断门相似,通过中断门进入服务程序后,自动关中断,而通过陷阱门进入服务程序不自动关中断。





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值