计算机组成
10 输入输出设备
10.5 外部中断的处理过程
我们之前已经学习了内部中断的处理方法,那么外部中断和内部中断总体上是很类似的。只是在一些具体的处理细节上和硬件的连接方式上有所不同。那我们现在就来看一看外部中断是如何处理的。
外部中断,也叫做硬件中断。这是由CPU外部的中断请求信号启动的中断。以x86 CPU为例,连到外部的中断请求信号一共有两个。一个信号叫做NMI,这就是非屏蔽中断的缩写。另一个信号叫INTR,这就是中断这个词的缩写,相对于非屏蔽中断,我们一般也称它为可屏蔽中断。不光是x86,其他很多别的体系结构的CPU也往往提供这两种类型的中断引脚。
这两个信号,是对应了CPU上真实存在的两个管脚。来自外设的中断请求信号就可以通过主板上的连线,连到这两个管脚上。这个NMI,也就是非屏蔽中断,一般会连接一个在这个系统当中非常重要,不希望被屏蔽的中断请求信号。那至于什么是非常重要,就取决于系统设计者的观点。例如在某些计算机当中,会将表示电池即将没电的这个信号连接到NMI上。电池马上就要没电了,确实是一个非常紧急的情况。因为非屏蔽中断是不受中断允许标志的影响,即使CPU现在将IF标志位设为0,关闭对外部中断的响应,CPU仍然会响应这个NMI的中断请求。这样就可以调用中断服务程序,在断电之前把一些重要的信息保存到硬盘上去。当然不同的系统可能会连接不同的中断请求信号到NMI上,但都会是一些非常重大,不处理就会导致严重错误的事件。
一般的外设,它的中断请求都会连接到可屏蔽中断上,但是CPU的可屏蔽中断信号的请求输入只有一根,那就需要通过一些转换电路。现在计算机当中比较常见的是使用中断控制器这个芯片。中断控制器会将外设输出的中断请求信号作为它的输入连接进来,然后输出一根信号连接到CPU的可屏蔽中断请求信号上。这个中断控制器也可以看作是一个I/O接口,它内部也有一些被称为I/O端口的寄存器,CPU可以访问这些端口,对中断控制器进行配置。例如可以配置这些外设的中断请求,哪个优先级高,哪个优先级低,或者可以在这些中断请求当中,屏蔽其中的一部分。这些都是中断控制器的基本功能。
因为这样的中断控制器是可以由编写程序进行配置的,所以又称为可编程中断控制器,简称PIC。有一个广泛使用的可编程中断控制器,就是英特尔的8259。我们可以看到8259上,从IR0一直到IR7,一共有8个中断请求的输入可以用来连接外设的中断请求信号。然后它还有一些地址和数据信号,用以连接到系统总线上。CPU对I/O端口的访问,就通过这些信号线来传递。INT信号则是由中断控制器发出的中断请求信号,连接到CPU的可屏蔽中断请求信号上。实际上CPU在收到中断请求后,还会发出一个中断响应信号,这个信号会被连接到中断控制器的INTA引脚上。
后来在8259的基础上,又有了一些升级和功能的扩充,这就是后来的高级可编程中断控制器,简称为APIC。
那么再来看一看中断控制器在系统当中的连接情况。
IBM PC/XT当中,就使用了一片8259。8259和CPU之间,有中断请求信号和中断响应信号。而另一端,8259则连接了来自各个外设的中断请求信号。比如有来自定时器,有键盘,有串行接口,有硬盘,有软盘,还有打印机。那2号中断请求信号是被保留的,并没有连接外设,等一会儿我们还会提到,这根保留的中断请求信号用来做什么。这是三十多年前最早的个人计算机。在现在的个人计算机当中,有些设备都已经没有了,比如软盘,但是现代的计算机系统仍然要遵守最早的个人计算机当中确定的一些规则。那么就以键盘所对应的这个中断为例,来看一看现在最新的个人计算机当中的情况。
如果我们在一台装了Windows操作系统的个人计算机上,调出设备管理器,然后在设备管理器中找到键盘,用右键看这个键盘的属性。我们就会发现,它的中断请求信号仍然是连接到中断控制器的1号接口,仍然遵守三十多年前IBM PC所制定的规范。
那在刚才的那个例子中我们可以看到,一个中断控制器最多可以连接七个外设。如果有更多的外设应该怎么办呢?我们可以在系统中再增加一个中断控制器,这个中断控制器的请求信号不是连接到CPU的,而是连接到原有的中断控制器的2号中断请求信号上。那在这个中断控制器上,又可以再连接更多的外设。这样两级中断控制器的结构,在早期的个人计算机当中使用了很长时间。
不过现在情况有一点不太一样,因为很多I/O接口都集成到了南桥当中。所以,这些I/O接口的中断请求信号实际上都是在南桥内部了。因此,在南桥内一般也会实现一个中断控制器,当然现在是APIC这样的中断控制器了。这个中断控制器负责接收所有I/O接口的中断请求信号,包括南桥内部集成的,和在外部独立的I/O接口。它会将中断请求信号再送到CPU中去。而现在的计算机当中,往往有多个CPU,其实每个CPU当中,都还会带一个中断控制器。因为现在的CPU不但要接受中断请求信号,它也会发出中断,现在CPU发出的中断,是用来跟别的CPU进行交互的。比如两个CPU要进行一些协同的工作,其中一个CPU在处理完了内存当中的一部分数据,它就可以通过发出中断请求来通知另一个CPU进行后续的工作。因此,在现代的个人计算机当中,可能已经找不到一个独立的中断控制器的芯片了,但其实中断控制器的功能已经变得更为丰富,数量也变得更多了。
我们还是回到简单的情况,来看看这些来自外设的,可屏蔽中断的处理过程。当外设有中断的需求,它就会通过中断控制器向CPU发出中断请求信号,而CPU则会中断当前正在执行的程序,向中断控制器发出中断响应信号,然后中断控制器再会通过其他的信号线,将对应外设的中断类型码发给CPU。而这个类型码,其实也是在系统初始化时,通过写入中断控制器的I/O端口而设置的。CPU在得到了中断类型码之后,后续的处理过程就和内部中断是一样的了。我们快速地浏览一遍。
CPU将相关的寄存器压栈,然后清除IF和TF标志位,再取得对应的中断向量。然后程序就会跳转到中断服务程序,在中断服务程序当中,可以在适当的时机通过设置IF标志位,开放中断。一旦开放了中断,就意味着在执行这个中断服务程序的过程中,CPU还可能会响应其他外设发来的中断。那在中断服务程序执行完之后,就会执行中断返回指令,将返回地址等信息从堆栈中弹出,然后就可以回到刚才被中断的位置继续执行了。如果在这个中断服务程序当中,开放中断后,外设又发来中断,那其实CPU是会中断这个中断服务程序的执行,转而去响应这个新发生的中断。这种情况就被称为中断嵌套。
当然,要想发生中断嵌套的情况,必须要有比当前正在处理的中断优先级更高的中断请求,那这时CPU就会去响应这个优先级更高的中断请求,在执行完这个新的中断服务程序之后,再返回到刚才的中断服务程序当中继续执行。
我们再根据图示来看一看这个过程。假设在一段主程序当中,开始是关闭了中断响应的。然后在这里打开了中断响应(STI),之后就发生了中断,于是CPU就会转向中断服务程序(第一层)。那么在这里CPU的硬件已经自动设置了IF标志位为0,屏蔽了外部的中断请求,如果在这个中断服务程序的某个地方(指第一层中的STI处)又打开了中断响应,而且在这个过程中又有外设发起了更高优先级的中断请求,那CPU又会去处理这个新的中断(第二层)。我们要注意,对于CPU来说,现在在执行的这个中断服务程序也就像是一个普通的程序,所以在这个过程中如果发生了中断请求,它依然会进行同样的那些处理步骤,比如压栈、关中断、保存现场等等,然后根据取回的中断向量进入到第二层的中断服务程序。那如果在这个中断服务程序当中没有开中断,或者开了中断但是没有更高优先级的外设发起中断请求,那一直执行到中断返回指令(IRET),CPU就会回到刚才发生中断的地方继续执行,也就是第一层的中断服务程序。如果之后没有再遇到中断请求,就会一直执行到第一层中断服务程序的中断返回指令(IRET),再返回到刚才主程序中断的地方。这就是一个简单的两层中断嵌套的过程。
现在我们已经知道了内部中断和外部中断是如何协同工作的,而在现代的计算机系统当中大量地使用了中断来控制输入输出设备。至于如何进行中断优先级的调配,什么时候能屏蔽中断,什么时候不能屏蔽中断,这些问题都是值得深入研究的。
原文地址:https://www.cnblogs.com/doctorx/p/9745217.html