漫谈计算机之中断概述

1,023 阅读4分钟

大部分内容来自北大课程 计算机组成,讲的实在是太好了!

CPU遇到的“事件”

如今的计算机功能越来越强大,CPU在执行的过程中,可能遇到一系列的特殊事件。例如,除数为0、结果溢出、输入输出设备中断等等。

对于这些事件,我们的处理流程一般如下:

  1. 在程序运行时,系统外部、内部或现行程序本身出现需要特殊处理的“事件”。
  2. CPU立即强行中止现行程序的运行,改变机器的工作状态并启动相应的程序来处理这些“事件”。
  3. 处理完成后,CPU恢复原来的程序运行。

以结果溢出来例,cpu的硬件电路是很容易检测出结果溢出的,但问题就在于检测到了溢出该怎么办?

一种方法是完全用硬件电路来处理溢出,这样显然不够灵活。一旦CPU制造出来,这个电路就固定了我们就无法改变了。从而没有办法改变处理溢出的方法。

除此之外,当有新类型的中断出现,计算机将无法正确处理,因为电路已经固定。

因此最好还是用软件的办法来解决。


处理特殊“事件”的思路

现代的计算机,采用一种中断向量表的方式来处理中断。

中断向量表,顾名思义是一张表。如下图:

左边的十六进制数是地址,右边的方框是中断向量表的内容。其中每四个方格组成一个中断向量,一共4个字节(图中相同颜色的框表示一个中断向量)。

image

这个中断向量表是在系统启动时进行初始化的(实模式下初始化),并且存放在固定的内存区域(例如,8086CPU将中断向量表存储在最低的1KB,存放了256个中断向量)。因此当系统接受到中断信号时,直接通过电路的设置就可以发出内存访问,来读取某个中断向量的内容。在8086CPU中,会将高两个字节的值送到CS寄存器,低两个字节的值送到IP寄存器(8086通过CS:IP来确定下一条指令的地址)。这样下一个周期CPU就会从这个地址取指令。我们已经在这个地址的位置上存放了处理该中断的处理程序,所以该中断就会得到处理。

这种方法扩展性和灵活性是很强的,当有新的中断加入时,我们只需要编写好中断处理程序,并且初始化好新的中断向量表就行。并且当我们要修改处理的方法,直接修改中断处理程序即可,不需要改变原来的硬件电路。可见软件的方法强大之处!


中断向量表的发展

以8086为例:

image

1.随着CPU发展,中断向量表的内容开始增多,8086有5个中断。

image

2.随着CPU的发展,CPU大多是运行在保护模式下的(实模式和保护模式的区别大家可以上网搜索,否则下文可能会看不懂)。

在不同模式下,指令的寻址发生了改变:

  1. 在实模式下 通过CS:IP
  2. 在保护模式下,通过CS:EIP

EIP是32位的寄存器,低16位代表IP,这是为了向上兼容。

保护模式下,段基址已经不存在CS中,而是内存中。 在内存中的某个地方,存放着一张表,称为段描述符表(表即数组)。这个表一共有2^16=8192个表项,每个表项由8个字节构成,称为一个段描述符。

image

图中可以看出,2,3,4,7字节代表基地址,这个地址就对应了实模式下保存在CS中的地址。段界限指明段的长度,权限指明段是否可读可写。

这块内存区域的基地址放在GDTR(全局描述符寄存器)里的。这张表是在实模式下建立的,并且把基地址给了GDTR。以后就可以通过GDTR找到这张表的基地址,然后利用CS寄存器定位某一个描述符(CS为16位,可以寻址8192个内存单元,刚好可以作为偏移)。

3.在保护模式下,中断向量表的位置发生了变化.

中断向量表不是存储在0地址开始的位置了,而是可以任意存储。名字也变成了中断描述符表。

其实和上面的实模式是类似的。不过这里我们需要IDTR(中断描述符表寄存器)来保存这张表的基地址。

字节0,1,7,6相当于EIP。段选择符将来放在CS中,通过GDTR:CS的方式找到取出段描述符的段基址。然后再用这个段基址:EIP找到对应的中断处理程序入口地址。

下一篇文章将告诉大家中断处理的过程。