从生活经验来看,一件具有有自主处理能力的设备,通常都具有一种能力,就是能够针对外部或者内部产生的一些非正常、异常的信息进行反应的能力。CPU作为人设计的机器的大脑,它也具有这样的能力,这种能为就是中断处理。中断处理处理的是中断信息,中断处理的过程是按照指定的中断信息执行指定的中断处理程序。学习中断需要了解的概念比较多,这里所描述的中断信息的概念,是为了理解上的方便采用的一种逻辑上的说法,它实际上是一些具有先后顺序的硬件操作所产生的事件的统一描述。我们按照中断产生的过程进行如下概念的分析。
1)中断源:引起中断的原因或者说发出中断请求的来源叫做中断源,可以根据中断源的不同,将中断分为硬件中断和软件中断。硬件中断又可分为来自己外设的外部中断和来自内部设备的内中断。外部中断一般是指由计算机外设发出的中断请求,如键盘中断、打印机中断、定时器中断等。外部中断一般是可以屏蔽的中断。内部中断是指因硬件出错如掉电、运算错等引起的中断。内部中断是不可屏蔽的中断。前面说的都是硬件中断,跟你的程序无关,还有一种可以主动触发的一些中断,通过程序和系统调用来进行。这类中断是软件中断,实际上并不是真正的中断,它是由运行程序主动发起为实现某种效果而调用的中断程序如INT 21H。前面说了中断一般拥有较高的执行级别,但是对同时来到的中断处理,它也是需要一个优先级别,通常是如下级别:除法错、溢出中断、软件中断--》不可屏蔽中断--》可屏蔽中断--》单步中断。
2)中断类型码,来自于不同中断源的不同信息,CPU需要进行标识,这个标识就是中断类型码,中断类型码是一个字节型数据,可表示256种中断信息的来源。
3)中断处理程序,CPU在接收到中断信息后,需要对中断信息进行处理,这个处理的程序称之为中断处理程序。通常这些处理程序是由操作系统提供,并存储在内存的指定位置。CPU根据中断类型码来确定具体的中断处理程序的起始位置。
4)中断向量表 前面说了CPU知道中断信息中的中断码,但是中断类型码只有8位,无法知道中断处理程序所在的段地址和偏移地址,因此需要有一个映射表,这个表就是中断向量表。中断向量表通常放在8086CPU的0号地址处,通常是0000:0000到0000:03FF这1024个内存单元中放着中断向量表。因为中断向量是按中断码顺序存储中断处理程序入口地址,对每一个入口地址是段地址加偏移地址组成也就是四个字节,通常是高地址是段地址,低地址是偏移地址。
5)中断处理(过程),前面CPU通过中断码查询中断向量表得到中断处理程序的入口地址,CPU将段地址和偏移地址设置为CS和IP。这个过程是由CPU的硬件自动完成,CPU完成的这个过程就称之为中断过程。当然这里不是仅仅这么简单的设置一下,因为处理完中断后,CPU通常还要回到原来的处理程序,所以CPU需要通过保存当前CS:IP,然后再设置中断的CS:IP,中断处理完子这后再弹出CS:IP。如下图所示:
下图是具体演示过程:
由上图可见,有相当一段操作是固定的,就是最后返回,通常使用iret指令返回。使用iret指令相当于pop IP pop CS popf。 iret通常和硬件自动完成的中断过程配合使用,当iret指令执行后,CPU回到执行中断处理程序前的执行点继续执行程序。如下图所示,除法错误,通常代表0号中断。
我们前面提到中断处理程序通常都是由操作系统来提供,那么可不可以自己提供一段中断处理程序,显然是可以的,通常前面的学习,我们只需要修改中断向量表中中断类型码对应的中断处理程序的入口段地址与偏移地址就行了。显然中断处理程序一定要始终占有一块内存,不能放在硬盘中。前面提到8086CPU通常占用前面1024个字节作为向量表的内存空间,但很明显不可能有这么多的向量表,因此最简单的存储自己中断处理程序的方法就是将自己写的中断处理程序放入这部分靠后的空间中。
assume cs:code
;data segment
; db "overflow!" ;不能将显示的字符串放在data区,需要放在真正内存空间里。
;date ends
code segment
start: mov ax,cs
mov ds,ax
mov si,offset do0 ;
mov ax,0
mov es,ax
mov di,200h
mov cx,offset do0end-offset do0 ;计算程序段长度
cld
rep movsb
mov ax,0
mov es,ax
mov word ptr es:[0*4],200h ;设置中断向量中中断类型码对应的中断处理程序的偏移地址
mov word ptr es:[0*4+2],0 ;设置中断向量中中断类型码对应的中断处理程序的段地址
mov ax,4c00h
int 21h
do0: jmp short do0start
db "Overflow!"
do0start: mov ax,cs
mov ds,ax
mov si,202h
mov ax,0b800h
mov es,ax
mov di,12*160+36*2 ;汇编编译器支持+ - * 表达式计算
mov cx,9
s: mov al,[si]
mov es:[di],al
inc si
add di,1
mov al,02h
mov es:[di],al
add di,1
loop s
mov ax,4c00h
int 21h
do0end: nop
code ends
end start
运行结果如下图:
CPU还提供了另外两种特殊中断能力,这两种特殊中断能力一个就是单步中断,另一个就是原子操作禁止中断。所谓单步中断,是指当CPU在执行完一条指令之后,如果检测到标志寄存器的TF=1时,则产生一个单步中断,引发中断过程。我们使用DEBUG调试程序也是利用了这个特性,当使用T命名时设置TF=1,然后进入DEBUG自己设置的中断处理程序。单步中断同前面所说的内部中断处理过程一样,但是需要注意其中一个步骤就是TF置0,通过这一步操作,显然可以避免无限循环的进行单步操作。
另外一个特性就是CPU在执行完向ss寄存器传送数据指令后,不执行除了修改SP的指令的任何指令,CPU使用这样的操作行为是为了避免栈顶错误。所以在开发时mov ss 之后一定时mov sp.否则中间的指令不会被CPU执行到。
前面所说的中断都是硬件中断,来源都是硬件错误(不论这个硬件是内部还外部的),还有一种中断是软件中断,这个中断是通过程序调用int指令主动发起的中断。int 指令的格式:int n,n为中断类型码,功能就是引发中断过程,进而执行中断处理程序(简称中断例程)。
assume cs:code
code segment
start: mov ax,3456
int 7ch
add ax,ax
adc dx,dx
mov ax,4c00h
int 21h
code ends
end start
在系统板的ROM中存放着主板商提供的一个标准BIOS(基本输入输出程序),这个程序和DOS也分别提供了一些标准的中断例程。那么他们是如何被加载到内存中呢,首先CPU加电后,初始化(CS)=0FFFFH (IP)=0,FFFF:0处有一跳转指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序。初始化程序建立BIOS所支持的中断向量,对BIOS提供的中断例程,只需要将入口地址登记在中断向量表中,因为它们是固化在ROM中,始终在内存中。硬件检测和初始化完成后,调用int 19h进行操作系统引导,这时进入DOS启动,启动过程中将DOS提供的中断例程装入内存,并设置相应的中断向量。
转载于:https://blog.51cto.com/acreep/733089