什么是中断和异常?
我和小李正在聊天,小杨过来找我借钱。这种场景,我和小李的聊天被打断——中断!
我和小李在聊天,鸟屎拉在我头上。这种场景,我不得不停止与小李的聊天——出现异常!
当中断和异常的情况发生之后,我需要有处理这些突发情况的能力,然后就会去处理中断(坚决不借钱给朋友,我昨天才买了股票啊,确实不好意思啊),处理异常(呵呵,去洗澡)!
在现实世界中,我有很多中断、异常处理的能力,也有一些我没有的能力(41楼,断电时刻,地震来了)
异常类型
在计算机世界中,CPU也有一些中断和异常处理的能力:如下图
在CPU执行指令的过程中,如果遇到列表中的中断,CPU有能力自己去处理这些中断和异常,同时为了扩展CPU的异常处理能力,程序员还可以使用向量号在32~255之间的向量去自定义异常
类型:
Fault:是一个可以被操作系统修正的异常类型,当Fault发生,CPU就跳转到该Fault的中断处理程序,一旦程序处理完毕,CPU就会重新执行引起Fault发生的这条指令。比如:当程序员去访问一个物理内存时,如果内存里还没有数据,就会抛出14 #PF Fault,然后操作系统的Fault处理程序,就会将数据从其他存储介质加载到内存,然后操作系统返回,CPU继续执行 程序员访问物理内存的那条指令
Trap: 当CPU执行完一条Trap指令之后,就会立即触发Trasp,然后执行Trasp处理程序,处理完毕之后,Cpu会继续执行Traps指令之后的那一条命令。比如:INT 3就是一个Trap 指令,在程序调试期间,遇到断点,调试器就可以执行调试,当调试完毕之后,就可以继续执行程序指令的下一跳指令
Abort: 这种异常发生之后,CPU并不报告是哪条指令引发。这种异常发生过后程序通常找不到错误原因,所以不能去修正。比如:在服务器端发生的 硬盘错误,非法值读取,系统总线出错等!
中断类型
CPU具有处理中断的能力,那中断是如何产生的呢?
中断分为两种
软中断:就是上表定义的各种中断,还有用户自定义的各种中断!当系统调用 int 19就产生了软中断
硬中断:CPU在执行指令期间,计算机的其他硬件比如内存,硬盘等发出的中断。比如:
- 系统时钟通过一个计数器(多基于某种振动频率)定期向CPU发出中断,CPU通过专门的时钟中断处理程序来保持计时。现代操作系统对系统时钟的另一个主要应用是为进程切换提供时机。一旦时钟中断发生,程序计数器会被自动压栈,而此时操作系统就有机会将程序状态及内存映像转存至别处,并调用进程调度程序来选择下一个进程,并将其进程状态,包括程序计数器,导入寄存器。这样下一个程序就可以运行。应注意进程调度程序的调度时机不止于时钟中断。
- 磁盘中断标识某个磁盘设备完成了数据的发送/接收。磁盘中断发生后,等待这个中断的进程可以(但未必,这取决于进程调度程序当时的判断)继续执行。
- 断电中断指示计算机能源即将丧失,计算机可以相应中断程序作有序的关机处理。
硬中断又分为两种:
- 不可屏蔽 :中断发生之后,CPU必须处理中断
- 可屏蔽:中断发生后,由于屏蔽了中断,CPU就当作没有发生中断
如何屏蔽中断
在CPU中有两个用来控制中断的控制器:可编程中断控制器8259A。
在初始化系统之前应该先将这两个控制器初始化,以确保中断处理正确。初始化必须遵守控制器的使用规则,过程如下:
; Init8259A ---------------------------- Init8259A: mov al, 011h out 020h, al ; 主8259, ICW1. call io_delay out 0A0h, al ; 从8259, ICW1. call io_delay mov al, 020h ; IRQ0 对应中断向量 0x20 out 021h, al ; 主8259, ICW2. call io_delay mov al, 028h ; IRQ8 对应中断向量 0x28 out 0A1h, al ; 从8259, ICW2. call io_delay mov al, 004h ; IR2 对应从8259 out 021h, al ; 主8259, ICW3. call io_delay mov al, 002h ; 对应主8259的 IR2 out 0A1h, al ; 从8259, ICW3. call io_delay mov al, 001h out 021h, al ; 主8259, ICW4. call io_delay out 0A1h, al ; 从8259, ICW4. call io_delay mov al, 11111110b ; 仅仅开启定时器中断 ;mov al, 11111111b ; 屏蔽主8259所有中断 out 021h, al ; 主8259, OCW1. call io_delay mov al, 11111111b ; 屏蔽从8259所有中断 out 0A1h, al ; 从8259, OCW1. call io_delay ret ; Init8259A --------------------------- io_delay: nop nop nop nop ret