更新时间:2022-08-25 16:42
中断是一种电信号,当设备有某种事件发生时,它就会产生中断,通过总线把电信号发送给中断控制器。硬中断是由硬件产生的,比如,像磁盘,网卡,键盘,时钟等。每个设备或设备集都有它自己的IRQ(中断请求)。基于IRQ,CPU可以将相应的请求分发到对应的硬件驱动上。
在计算机系统中,CPU在正常运行程序时,由于程序的预先安排或内外事件,引起CPU中断正在运行的程序,而转到为预先安排的事件或内外事件服务的程序中去,这就是常称的中断。当由于执行某些指令引起的中断,如DIV指令,除数为0时产生的中断为软中断;CPU本身也有两条中断请求线:非屏蔽中断,和可屏蔽中断线。当这两条线上收到中断请求信号而引起的中断,则产生了硬中断。硬中断是一个异步信号,或需要改变在执行一个同步事件。硬中断是一种在轮询循环,等待外部事件方面避免浪费处理器的宝贵时间的方式。作为一个独立的有控制线系统,它们可以在硬件中实现或被集成到存储器子系统。硬中断就是通常意义上的“中断处理程序”,它是直接处理由硬件发过来的中断信号的。当硬中断收到它应当处理的中断信号以后,就回去自己驱动的设备上去看看设备的状态寄存器以了解发生了什么事情,并进行相应的操作。
Linux下硬中断是可以嵌套的,但是没有优先级的概念,也就是说任何一个新的中断都可以打断正在执行的中断,但同种中断除外。软中断不能嵌套,但相同类型的软中断可以在不同CPU上并行执行。
软中断是一组静态定义的下半部分接口,可以在所有的处理器上同时执行,即使两个类型相同也可以。但是一个软中断不会抢占另外的一个软中断,可以抢占软中断的硬中断。
为了满足实时系统的要求,中断处理应该越快越好。编写驱动程序的时候,一个中断产生之后,内核在中断处理函数中可能需要完成很多工作。但是中断处理函数的处理是关闭了中断的。也就是说在响应中断时,系统不能再次响应外部的其它中断。这样的后果会造成有可能丢失外部中断。于是,Linux内核设计出了一种架构,中断函数需要处理的任务分为两部分,一部分在中断处理函数中执行,这时系统关闭中断。另外一部分在软件中断中执行,这个时候开启中断,系统可以响应外部中断。软中断是执行中断指令产生的,而硬中断是由外设引发的。硬中断的中断号是由中断控制器提供的,软中断的中断号由指令直接指出,无需使用中断控制器。硬中断是可屏蔽的,软中断不可屏蔽。硬中断处理程序要确保它能快速地完成任务,这样程序执行时才不会等待较长时间,称为上半部。软中断处理硬中断未完成的工作,是一种推后执行的机制,属于下半部。
硬中断可以分为以下几种:
可屏蔽中断(maskable interrupt)。硬件中断的一类,可通过在中断屏蔽寄存器中设定位掩码来关闭。
非可屏蔽中断(non-maskable interrupt,NMI)。硬件中断的一类,无法通过在中断屏蔽寄存器中设定位掩码来关闭。典型例子是时钟中断(一个硬件时钟以恒定频率—如50Hz—发出的中断)。
处理器间中断(interprocessor interrupt)。一种特殊的硬件中断。由处理器发出,被其它处理器接收。仅见于多处理器系统,以便于处理器间通信或同步。
伪中断(spurious interrupt)。一类不希望被产生的硬件中断。发生的原因有很多种,如中断线路上电气信号异常,或是中断请求设备本身有问题。
在微机系统中,对于外部中断,中断请求信号是由外部设备产生,并施加到CPU的NMI或INTR引脚上,CPU通过不断地检测NMI和INTR引脚信号来识 别是否有中断请求发生。对于内部中断,中断请求方式不需要外部施加信号激发,而是通过内部中断控制逻辑去调用。无论是外部中断还是内部中断,中断处理过程 都要经历以下步骤:请求中断→响应中断→关闭中断→保留断点→中断源识别→保护现场→中断服务子程序→恢复现场→中断返回。
当某一中断源需要CPU为其进行中断服务时,就输出中断请求信号,使中断控制系统的中断请求触发器置位,向CPU请求中断。系统要求中断请求信号一直保持到CPU对其进行中断响应为止。
CPU对系统内部中断源提出的中断请求必须响应,而且自动取得中断服务子程序的入口地址,执行中断 服务子程序。对于外部中断,CPU在执行当前指令的最后一个时钟周期去查询INTR引脚,若查询到中断请求信号有效,同时在系统开中断(即IF=1)的情 况下,CPU向发出中断请求的外设回送一个低电平有效的中断应答信号,作为对中断请求INTR的应答,系统自动进入中断响应周期。
CPU响应中断后,输出中断响应信号,自动将状态标志寄存器FR或EFR的内容压入堆栈保护起来,然后将FR或EFR中的中断标志位IF与陷阱标志位TF清零,从而自动关闭外部硬件中断。因为CPU刚进入中断时要保护现场,主要涉及堆栈操作,此时不能再响应中断,否则将造成系统混乱。
保护断点就是将CS和IP/EIP的当前内容压入堆栈保存,以便中断处理完毕后能返回被中断的原程序继续执行,这一过程也是由CPU自动完成。
当系统中有多个中断源时,一旦有中断请求,CPU必须确定是哪一个中断源提出的中断请求,并由中断控制器给出中断服务子程序的入口地址,装入CS与IP/EIP两个寄存器。CPU转入相应的中断服务子程序开始执行。
主程序和中断服务子程序都要使用CPU内部寄存器等资源,为使中断处理程序不破坏主程序中寄存器的内容,应先将断点处各寄存器的内容压入堆栈保护起来,再进入的中断处理。现场保护是由用户使用PUSH指令来实现的。
中断服务是执行中断的主体部分,不同的中断请求,有各自不同的中断服务内容,需要根据中断源所要完成的功能,事先编写相应的中断服务子程序存入内存,等待中断请求响应后调用执行。
当中断处理完毕后,用户通过POP指令将保存在堆栈中的各个寄存器的内容弹出,即恢复主程序断点处寄存器的原值。
在中断服务子程序的最后要安排一条中断返回指令IRET,执行该指令,系统自动将堆栈内保存的 IP/EIP和CS值弹出,从而恢复主程序断点处的地址值,同时还自动恢复标志寄存器FR或EFR的内容,使CPU转到被中断的程序中继续执行。
处理硬件中断的驱动程序对所有分配的内存有严格的要求。所有在中断期间要访问的代码和数据都必须是固定的、页码锁定的和不可废弃的。这包括中断处理函数本身的代码以及在中断处理过程中要用到的驱动程序代码段、任何动态分配的缓冲区和应用程序分配的要传递给驱动程序的缓冲区。
内存要求必须是固定的。因为内存管理器把中断处理函数要用到的数据段移动了,在一些字节被拷贝后,硬件中断发生,这时硬件中断处理函数被执行。硬件中断处理函数会更新正在移动的数据段中的一些内容,当处理函数结束运行之后,内存管理器接着移动数据段,而这时的数据段已经被处理函数更改过了。内存管理器并不知道处理函数已经改变了数据。而使用该数据段的应用程序就得不到希望得到的数据。
同时内存又要求必须是页面锁定的。假设硬件中断发生了,而内存管理器是在可废弃的代码中,那么就会发生段不在内存中的警告,在此种情况下就有可能发生重入 DOS 的情况,而 DOS 代码是不可重入的,所以代码段是不可废弃的。