内中断

任何一种CPU都可以执行这样的操作,也就是在执行指令的过程中,突然检测到从CPU内部或者外部发送过来或是产生的一种特殊信息,CPU要先处理这个特殊信息,然后再去继续执行指令。这种特殊的信息称为中断信息。而本章的内中断就是指CPU内部产生的中断信息。

1.内中断的产生

当CPU有下列特殊情况发生时候,会产生中断信息

1.除法错误,比如div产生除法溢出。(中断码:0)

2.单步执行。(中断码:1)

3.执行into指令。(中断码:4)

4.执行int指令。(该指令的格式位int n,n为字节型立即数,为中断码。)

接收到这4种不同的信息,就要进行不同的处理。因为中断信息来源不同,比如上面4种,那么就要有编码来对不同事件编码区分,叫做中断类型码,为一个字节型数据,可以表示256种中断信息的来源。

2.中断程序处理

对中断信息处理需要我们编程决定。一般对不同的中断信息写不同的程序。要执行某处的程序,就要将CS:IP指向它的入口(也就是程序第一条指令的地址)。所以重要的问题时,CPU收到中断信息后,如何根据中断信息确定其处理程序的入口。所以CPU需要在中断信息和程序入口之间建立联系。

根据中断码,比如4,CPU可以找到4号中断的处理程序。但是若要定位处理程序,如何知道段地址和偏移地址?

3.中断向量表

image-20231205011151868

中断向量就是中断处理程序的入口地址。

表中一共256个向量(地址)存放着256个中断源对应的中断处理程序的入口。如图所示。

问题是,CPU如何找到中断向量表?要先找到中断向量表才能通过中断码找到中断处理程序入口地址。

中断向量表在内存中存放,对于8086,指定放在内存地址0处。从0000:0000到0000:03FF的1024个单元(共1024个字节的位置)中存放着中断向量表。

在表中,每一项占两个字(每个字2个字节,两个字4个字节,所以256个中断程序地址正好存放),存放中断处理程序的入口地址。(高地址存放段,低地址存放偏移地址

看一个例题

image-20231205012259751

3号中断其实是第四个,前三号占12个字节,第四个也就是12-15,对应着0070018B两个字。段地址0070偏移地址018B。

image-20231205012720919

N号实际上是N+1个,前N个占据了从0到N*4-1,所以新的从0000:(0000+4N)开始到0000:(0000+4N+3)。

所以存储偏移地址的内存单元地址为4N,存储段地址的内存单元地址为4N+2。

4.中断过程

使用中断码,在中断向量列表找到要执行中断处理程序的程序入口的段地址和偏移地址。这是CPU要进行的操作,这个工作是由CPU的硬件自动完成的。在设置CS:IP之前,还要将原来的CS:IP保存。在使用call指令调用时也出现同样的问题,要提前保存退出子程序后还要继续使用的变量。

所以工作原理如下:

1
2
3
4
5
6
1.从中断信息获得中断类型码。
2.标志寄存器值入栈(因为中断过程会改变其值,所以提前保存)
3.设置标志寄存器第8位TF和第9位IF为0(后面解释)
4.CS入栈
5.IP入栈
6.从内存地址为中断类型码*4和中断类型码*4+2中读取要设置的CS:IP。

用编程描述如下:

1
2
3
4
5
6
7
取得中断类型码N
pushf//标志寄存器入栈
TF=0,IF=0
push CS
push IP
(IP) = (4*N), (CS) = (4*N+2)
然后开始执行中断处理程序

5.中断处理程序和iret指令

因为CPU随时会检测到中断信息,所以中断处理程序必须一直存储在内存某一段空间之中。而入口地址,即中断向量必须存储在对应的中断向量表中。

中断处理程序的编写和子程序比较像

1
2
3
4
1.保存用到的寄存器
2.处理中断
3.恢复用到的寄存器
4.用iret指令返回。

iret指令原理为

1
2
3
pop IP
pop CS出栈保存的寄存器,出栈保存的标志寄存器
popf

6.除法错误中断的处理

也就是0号中断。检测到此中断后,执行0号中断对应的中断处理程序。我们看一下对下面程序的执行结果

1
2
3
mov ax,1000h
mov bh,1
div bh

image-20231205020010684

可以看到发生溢出错误。0号中断处理程序的功能:显示信息”Divide overflow”后返回到操作系统中。

7.编程处理0号中断

也就是我们改写一下这个0号中断处理程序。改成在屏幕中间显示”overflow!”然后返回到操作系统。

image-20231205020204546

如图所示。