0号中断也被成为除法错误中断,本文将演示发生触发错误之后,走我们自己的代码,在屏幕上显示ByZero
中断
可屏蔽中断: 程序执行时,可以被其他事件打断,例如鼠标,键盘等事件,这种事件叫做中断,这种中断是可以被禁止的,因为如果CPU有更重要的事情要做,那么就可以让键盘和鼠标等中断无效,可屏蔽中断的信号是通过CPU的INTR引脚传递的
不可屏蔽中断: 程序执行时候,如果有不可抗拒的事件发生,那么这个中断原则上是不应该被屏蔽的,应该随时有效,例如低电量警告,不可屏蔽中断的信号是通过CPU的NMI引脚传递的
笔记: 不可屏蔽中断只是原则上不可屏蔽,其实也能屏蔽,本文将会使用这种方式
中断向量表
当一个中断发生时,肯定要有一个程序(代码)对这个中断进行处理,那么CPU如何知道这个代码在哪里呢?这个时候就需要中断向量表,在实模式下,内存0到0x3FF的1024个字节被用作中断向量表(上图1,),每个中断,占4个字节,所以一共有256个中断,分别被编号为0号中断,1号中断…N号中断(下图2),这些中断号都是协商好的,通常我们个人不会去更改,根据这个规则,我们可以根据中断号,乘以4,找到该中断号所对应的中断程序的起始地址,示例:
示例1:发生了1号中断,则1号中断程序
偏移地址是:1乘以4=4,所以偏移地址在内存4和5处
段地址是:4+2=6,所以段地址在内存6和7处
示例2:发生了112号中断,则112号中断程序
偏移地址是:112乘以4=448,所以偏移地址在内存448和449处
段地址是:448+2=450,所以段地址在内存450和451处
根据上述可知,如果发生了N号中断,则N号程序对应的
偏移地址:N乘以4
段地址是:偏移地址+2
注意:中断是一个使用栈的过程,当发生中断的时候,会压入当前的CS/IP寄存器(先压IP后压CS)和标志寄存器,然后TF和IF置0,也叫做保留现场,当中断结束时,会弹出CS/IP和标志寄存器来恢复之前运行的代码
因为上述原因,所以当修改ss寄存器的时候,CPU会屏蔽所有中断,直到下一条指令结束,例如下面代码
mov ss,ax ;执行这行代码的时候,cpu强制屏蔽中断
mov eax,0xb8000 ;这行代码执行完毕的时候,cpu将解除屏蔽中断
但是上面的代码是没有意义的,cpu屏蔽中断的目的是让我们修改ss之后,马上修改sp,所以下面的代码是合理的
mov ss,ax ;执行这行代码的时候,cpu强制屏蔽中断
mov sp,0x7c00 ;这样ss和sp就都被修改了
使用到的新汇编指令
cli
cli ;这个命令没有任何操作数,直接使用即可
;使用之后标志寄存器的IF位会置0,表示屏蔽其他可屏蔽中断
sti
sti ;同cli一样,只不过会将IF位置1
iret
iret ;用于中断程序返回使用,因为中断发生时,为了保存现场,会先压入
;标志寄存器,IP,还有CS,这样为了恢复现场,使用iret等同于
;弹出CS,IP,还有标志寄存器
hlt
hlt ;CPU会卡在这个位置,直到有中断发生,低功耗
mov ax,0 ;安装0号中断程序show_by_zero
mov ds,ax
mov word [0],show_by_zero+0x7c00
mov word [2],0
mov ax,1
mov bx,0
div bx
dont_stop:
hlt
jmp dont_stop
show_by_zero:
mov ax,0xb800
mov ds,ax
mov byte [0], 'B'
mov byte [1], 0x0b
mov byte [2], 'y'
mov byte [3], 0x0b
mov byte [4], 'Z'
mov byte [5], 0x0b
mov byte [6], 'e'
mov byte [7], 0x0b
mov byte [8], 'r'
mov byte [9], 0x0b
mov byte [10],'o'
mov byte [11],0x0b
iret
times 510-($-$$) db 0
dw 0xAA55